Pārlūkot izejas kodu

merged 6.x-0.4-dev from before the coding standards re-write

Lacey Sanderson 12 gadi atpakaļ
vecāks
revīzija
13f1b69a3c

+ 207 - 66
tripal_core/mviews.php

@@ -11,7 +11,11 @@
  */
 
 /**
- * Add a materialized view to the chado database to help speed data access.
+ * Add a materialized view to the chado database to help speed data access. This
+ * function supports the older style where postgres column specifications 
+ * are provided using the $mv_table, $mv_specs and $indexed variables. It also
+ * supports the newer preferred method where the materialized view is described
+ * using the Drupal Schema API array.  
  *
  * @param $name 
  *   The name of the materialized view.
@@ -26,22 +30,36 @@
  * @param $query 
  *   The SQL query that loads the materialized view with data
  * @param $special_index  
- *   function
+ *   currently not used
+ * @param $comment
+ *   A string containing a description of the materialized view
+ * @param $mv_schema
+ *   If using the newer Schema API array to define the materialized view then
+ *   this variable should contain the array.
  *
  * @ingroup tripal_mviews_api
  */
-function tripal_add_mview ($name,$modulename,$mv_table,$mv_specs,$indexed,$query,$special_index,$comment=NULL){
+function tripal_add_mview ($name, $modulename, $mv_table, $mv_specs, $indexed,
+   $query, $special_index, $comment=NULL, $mv_schema=NULL)
+{
+   // get the table name from the schema array
+   $schema_arr = array();
+   if($mv_schema){
+      // get the schema from the mv_specs and use it to add the custom table
+      eval("\$schema_arr = $mv_schema;");
+      $mv_table = $schema_arr['table'];
+   }
 
    $record = new stdClass();
    $record->name = $name;
    $record->modulename = $modulename;
-   $record->mv_schema = 'DUMMY';
    $record->mv_table = $mv_table;
    $record->mv_specs = $mv_specs;
    $record->indexed = $indexed;
    $record->query = $query;
    $record->special_index = $special_index;
    $record->comment = $comment;
+   $record->mv_schema = $mv_schema;
 
    // add the record to the tripal_mviews table and if successful
    // create the new materialized view in the chado schema
@@ -67,24 +85,34 @@ function tripal_add_mview ($name,$modulename,$mv_table,$mv_specs,$indexed,$query
         }
       }
 
-      // add the table to the database
-      $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
-      $previous_db = tripal_db_set_active('chado');  // use chado database
-      $results = db_query($sql);
-      tripal_db_set_active($previous_db);  // now use drupal database
-      if($results){
-         drupal_set_message(t("View '$name' created"));
+      // create the table differently depending on if it the traditional method
+      // or the Drupal Schema API method
+      if($mv_schema){
+         if(!tripal_create_chado_table ($ret,$mv_table,$schema_arr)){
+            drupal_set_message("Could not create the materialized view. Check Drupal error report logs.");
+         } else {
+            drupal_set_message(t("View '$name' created"));
+         }
       } else {
-         // if we failed to create the view in chado then
-         // remove the record from the tripal_jobs table
-         $sql = "DELETE FROM {tripal_mviews} ".
-                "WHERE mview_id = $record->mview_id";
-         db_query($sql);
+         // add the table to the database
+         $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
+         $previous_db = tripal_db_set_active('chado');  // use chado database
+         $results = db_query($sql);
+         tripal_db_set_active($previous_db);  // now use drupal database
+         if($results){
+            drupal_set_message(t("View '$name' created"));
+         } else {
+            drupal_set_message(t("Failed to create the materialized view table: '$mv_table'"));
+         }
       }
    }
 }
 /**
- * Edits a materialized view to the chado database to help speed data access.
+ * Edits a materialized view to the chado database to help speed data access.This
+ * function supports the older style where postgres column specifications 
+ * are provided using the $mv_table, $mv_specs and $indexed variables. It also
+ * supports the newer preferred method where the materialized view is described
+ * using the Drupal Schema API array.  
  *
  * @param $mview_id 
  *   The mview_id of the materialized view to edit
@@ -101,17 +129,32 @@ function tripal_add_mview ($name,$modulename,$mv_table,$mv_specs,$indexed,$query
  * @param $query 
  *   The SQL query that loads the materialized view with data
  * @param $special_index  
- *   function
+ *   currently not used
+ * @param $comment
+ *   A string containing a description of the materialized view
+ * @param $mv_schema
+ *   If using the newer Schema API array to define the materialized view then
+ *   this variable should contain the array.
  *
  * @ingroup tripal_mviews_api
  */
-function tripal_edit_mview ($mview_id,$name,$modulename,$mv_table,$mv_specs,$indexed,$query,$special_index,$comment){
+function tripal_edit_mview ($mview_id,$name,$modulename,$mv_table,$mv_specs,
+   $indexed,$query,$special_index,$comment=NULL,$mv_schema=NULL)
+{
+
+   // get the table name from the schema array
+   $schema_arr = array();
+   if($mv_schema){
+      // get the schema from the mv_specs and use it to add the custom table
+      eval("\$schema_arr = $mv_schema;");
+      $mv_table = $schema_arr['table'];
+   }
 
    $record = new stdClass();
    $record->mview_id = $mview_id;
    $record->name = $name;
    $record->modulename = $modulename;
-   $record->mv_schema = 'DUMMY';
+   $record->mv_schema = $mv_schema;
    $record->mv_table = $mv_table;
    $record->mv_specs = $mv_specs;
    $record->indexed = $indexed;
@@ -154,20 +197,24 @@ function tripal_edit_mview ($mview_id,$name,$modulename,$mv_table,$mv_specs,$ind
            $index .= "CREATE INDEX idx_${mv_table}_${field} ON $mv_table ($field);";
         }
       }
-
-      // recreate the view
-      $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
-      $previous_db = tripal_db_set_active('chado');  // use chado database
-      $results = db_query($sql);
-      tripal_db_set_active($previous_db);  // now use drupal database
-      if($results){
-         drupal_set_message(t("View '$name' edited and saved.  All results cleared. Please re-populate the view."));
+      // re-create the table differently depending on if it the traditional method
+      // or the Drupal Schema API method
+      if($mv_schema){         
+         if(!tripal_create_chado_table ($ret,$mv_table,$schema_arr)){
+            drupal_set_message("Could not create the materialized view. Check Drupal error report logs.");
+         } else {
+            drupal_set_message(t("View '$name' created"));
+         }
       } else {
-         // if we failed to create the view in chado then
-         // remove the record from the tripal_jobs table
-         $sql = "DELETE FROM {tripal_mviews} ".
-                "WHERE mview_id = $record->mview_id";
-         db_query($sql);
+         $sql = "CREATE TABLE {$mv_table} ($mv_specs); $index"; 
+         $previous_db = tripal_db_set_active('chado');  // use chado database
+         $results = db_query($sql);
+         tripal_db_set_active($previous_db);  // now use drupal database
+         if($results){
+            drupal_set_message(t("View '$name' edited and saved.  All results cleared. Please re-populate the view."));
+         } else {
+            drupal_set_message(t("Failed to create the materialized view table: '$mv_table'"));
+         }
       }
    }
 }
@@ -251,10 +298,10 @@ function tripal_update_mview ($mview_id){
    if($mview){
       $previous_db = tripal_db_set_active('chado');  // use chado database
 	   $results = db_query("DELETE FROM {$mview->mv_table}");
-      $results = db_query("INSERT INTO $mview->mv_table ($mview->query)");
+      $results = db_query("INSERT INTO {$mview->mv_table} ($mview->query)");
       tripal_db_set_active($previous_db);  // now use drupal database
       if($results){
-         $sql = "SELECT count(*) as cnt FROM $mview->mv_table";
+         $sql = "SELECT count(*) as cnt FROM {$mview->mv_table}";
          $count = db_fetch_object(db_query($sql));
 	      $record = new stdClass();
          $record->mview_id = $mview_id;
@@ -413,9 +460,9 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
 
    // get this requested view
    if(strcmp($action,'Edit')==0){
-      $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = $mview_id ";
-      $mview = db_fetch_object(db_query($sql));
-
+      $sql = "SELECT * FROM {tripal_mviews} WHERE mview_id = %d ";
+      $mview = db_fetch_object(db_query($sql,$mview_id));
+      
       # set the default values.  If there is a value set in the 
       # form_state then let's use that, otherwise, we'll pull 
       # the values from the database 
@@ -446,6 +493,26 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
       }
       if(!$default_comment){
          $default_comment = $mview->comment;
+      }      
+      if(!$default_schema){
+         $default_schema = $mview->mv_schema;
+      }
+      // the mv_table column of the tripal_mviews table always has the table 
+      // name even if it is a custom table. However, for the sake of the form,
+      // we do not want this to show up as the mv_table is needed for the 
+      // traditional style input.  We'll blank it out if we have a custom 
+      // table and it will get reset in the submit function using the 
+      // 'table' value from the schema array
+      if($default_schema){
+         $default_mv_table = '';
+      }
+      
+      // set which fieldset is collapsed 
+      $schema_collapsed = 0;      
+      $traditional_collapsed = 1;
+      if(!$default_schema){
+         $schema_collapsed = 1;      
+         $traditional_collapsed = 0;
       }
    }
    // Build the form
@@ -463,58 +530,80 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
       '#description'   => t('Please enter the name for this materialized view.'),
       '#required'      => TRUE,
       '#default_value' => $default_name,
-      '#weight'        => 1
+   );
+   $form['comment']= array(
+      '#type'          => 'textarea',
+      '#title'         => t('MView Description'),
+      '#description'   => t('Optional.  Please provide a description of the purpose for this materialized vieww.'),
+      '#required'      => FALSE,
+      '#default_value' => $default_comment,
    );
 
-   $form['mv_table']= array(
+   // add a fieldset for the Drupal Schema API
+   $form['schema'] = array(
+     '#type' => 'fieldset',
+     '#title' => 'Drupal Schema API Setup',
+     '#description' => t('Use the Drupal Schema API array to describe a table. The benefit is that it '.
+                         'can be fully integrated with Tripal Views.  Tripal supports an extended '.
+                         'array format to allow for descriptoin of foreign key relationships.'),
+     '#collapsible' => 1,
+     '#collapsed' => $schema_collapsed ,
+   );
+   $form['schema']['schema']= array(
+      '#type'          => 'textarea',
+      '#title'         => t('Schema Array'),
+      '#description'   => t('Please enter the Drupal Schema API compatible array that defines the table.'),
+      '#required'      => FALSE,
+      '#default_value' => $default_schema,
+      '#rows'          => 25,
+   ); 
+   // add a fieldset for the Original Table Description fields
+   $form['traditional'] = array(
+     '#type' => 'fieldset',
+     '#title' => 'Traditional MViews Setup',
+     '#description' => t('Traidtionally with Tripal MViews were created by specifying PostgreSQL style '.
+                         'column types.  This method can be used but is deprecated in favor of the '.
+                         'newer Drupal schema API method provided above.'),
+     '#collapsible' => 1,
+     '#collapsed' => $traditional_collapsed,
+   ); 
+   $form['traditional']['mv_table']= array(
       '#type'          => 'textfield',
       '#title'         => t('Table Name'),
-      '#description'   => t('Please enter the Postgres table name that this view will generate in the database.  You can use the schema and table name for querying the view'),
-      '#required'      => TRUE,
+      '#description'   => t('Please enter the table name that this view will generate in the database.  You can use the schema and table name for querying the view'),
+      '#required'      => FALSE,
       '#default_value' => $default_mv_table,
-      '#weight'        => 3
    );
-   $form['mv_specs']= array(
+   $form['traditional']['mv_specs']= array(
       '#type'          => 'textarea',
       '#title'         => t('Table Definition'),
       '#description'   => t('Please enter the field definitions for this view. Each field should be separated by a comma or enter each field definition on each line.'),
-      '#required'      => TRUE,
+      '#required'      => FALSE,
       '#default_value' => $default_mv_specs,
-      '#weight'        => 4
    );
-   $form['indexed']= array(
+   $form['traditional']['indexed']= array(
       '#type'          => 'textarea',
       '#title'         => t('Indexed Fields'),
       '#description'   => t('Please enter the field names (as provided in the table definition above) that will be indexed for this view.  Separate by a comma or enter each field on a new line.'),
       '#required'      => FALSE,
       '#default_value' => $default_indexed,
-      '#weight'        => 5
-   );
-   $form['mvquery']= array(
-      '#type'          => 'textarea',
-      '#title'         => t('Query'),
-      '#description'   => t('Please enter the SQL statement used to populate the table.'),
-      '#required'      => TRUE,
-      '#default_value' => $default_mvquery,
-      '#weight'        => 6
    );
 /**
-   $form['special_index']= array(
+   $form['traditional']['special_index']= array(
       '#type'          => 'textarea',
       '#title'         => t('View Name'),
       '#description'   => t('Please enter the name for this materialized view.'),
       '#required'      => TRUE,
       '#default_value' => $default_special_index,
-      '#weight'        => 7
    );
 */
-   $form['comment']= array(
+   $form['mvquery']= array(
       '#type'          => 'textarea',
-      '#title'         => t('MView Description'),
-      '#description'   => t('Optional.  Please provide a description of the purpose for this materialized vieww.'),
-      '#required'      => FALSE,
-      '#default_value' => $default_comment,
-      '#weight'        => 8
+      '#title'         => t('Query'),
+      '#description'   => t('Please enter the SQL statement used to populate the table.'),
+      '#required'      => TRUE,
+      '#default_value' => $default_mvquery,
+      '#rows'          => 25,
    );
    if($action == 'Edit'){
       $value = 'Save';
@@ -537,7 +626,56 @@ function tripal_mviews_form(&$form_state = NULL,$mview_id = NULL){
 *
 * @ingroup tripal_core
 */
+function tripal_mviews_form_validate($form, &$form_state){
+   $action = $form_state['values']['action'];
+   $mview_id = $form_state['values']['mview_id'];
+   $name = $form_state['values']['name'];
+   $mv_table = $form_state['values']['mv_table'];
+   $mv_specs = $form_state['values']['mv_specs'];
+   $indexed = $form_state['values']['indexed'];
+   $query = $form_state['values']['mvquery'];
+   $special_index = $form_state['values']['special_index'];
+   $comment = $form_state['values']['comment'];
+   $schema = $form_state['values']['schema'];
+   
+   if($schema and ($mv_table or $mv_specs or $indexed or $special_index)){
+       form_set_error($form_state['values']['schema'], 
+          t('You can create an MView using the Drupal Schema API method or the '.
+            'traditional method but not both.'));
+   }
+   if(!$schema){
+      if(!$mv_specs){
+         form_set_error($form_state['values']['mv_specs'], 
+            t('The Table Definition field is required.'));
+      }
+      if(!$mv_table){
+         form_set_error($form_state['values']['mv_table'], 
+            t('The Table Name field is required.'));
+      }
+   }
+   
+   // make sure the array is valid
+   if($schema){
+      $success = eval("\$schema_array = $schema;");
+      if ($success === FALSE){
+         $error = error_get_last();
+         form_set_error($form_state['values']['schema'], 
+            t("The schema array is improperly formatted. Parse Error : " . $error["message"]));
+      }
+      if(!array_key_exists('table',$schema_array)){
+         form_set_error($form_state['values']['schema'], 
+            t("The schema array must have key named 'table'"));
+      } 
+      // TODO: add in more validation checks of the array to help the user
+   }
+}
+/**
+*
+*
+* @ingroup tripal_core
+*/
 function tripal_mviews_form_submit($form, &$form_state){
+   $ret = array();
    
    $action = $form_state['values']['action'];
    $mview_id = $form_state['values']['mview_id'];
@@ -548,12 +686,15 @@ function tripal_mviews_form_submit($form, &$form_state){
    $query = $form_state['values']['mvquery'];
    $special_index = $form_state['values']['special_index'];
    $comment = $form_state['values']['comment'];
+   $schema = $form_state['values']['schema'];
 
    if(strcmp($action,'Edit')==0){
-      tripal_edit_mview($mview_id,$name, 'tripal_core',$mv_table, $mv_specs,$indexed,$query,$special_index,$comment);
+      tripal_edit_mview($mview_id,$name, 'tripal_core',$mv_table, $mv_specs,
+         $indexed,$query,$special_index,$comment,$schema);
    }
    else if(strcmp($action,'Add')==0){
-      tripal_add_mview ($name, 'tripal_core',$mv_table, $mv_specs,$indexed,$query,$special_index,$comment);
+      tripal_add_mview ($name, 'tripal_core',$mv_table, $mv_specs,
+         $indexed,$query,$special_index,$comment,$schema);
    }
    else {
         drupal_set_message("No action performed.");

+ 98 - 0
tripal_core/tripal_core.api.inc

@@ -1890,3 +1890,101 @@ function tripal_get_max_chado_rank ($tablename, $where_options) {
 		return -1;
 	}
 }
+
+/**
+ * Add a new table to the Chado schema. This function is simply a wrapper for
+ * the db_create_table() function of Drupal, but ensures the table is created
+ * inside the Chado schema rather than the Drupal schema.  If the table already
+ * exists then it will be dropped and recreated using the schema provided.
+ * Howver, it will only drop a table if it exsits in the tripal_custom_tables
+ * table. This way the function cannot be used to accidentally alter existing
+ * non custom tables.
+ *
+ * @param $ret
+ *   Array to which query results will be added.
+ * @param $table
+ *   The name of the table to create.
+ * @param $schema
+ *   A Drupal-style Schema API definition of the table
+ *
+ * @return
+ *   A database query result resource for the new table, or FALSE if table was not constructed.
+ *
+ * @ingroup tripal_core_api
+ */
+function tripal_create_chado_table (&$ret,$table,$schema) {
+   $ret = array();
+
+   // If the table exits in Chado but not in the tripal_custom_tables field
+   // then call an error.  if the table exits in the tripal_custom_tables but
+   // not in Chado then create the table and replace the entry.
+   $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_name = '%s'";
+   $centry = db_fetch_object(db_query($sql,$table));
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $exists = db_table_exists($table);
+   tripal_db_set_active($previous_db);  // now use drupal database
+   if(!$exists){
+      $previous_db = tripal_db_set_active('chado');  // use chado database
+      db_create_table($ret,$table,$schema);
+      tripal_db_set_active($previous_db);  // now use drupal database
+      if(count($ret)==0){
+   	   watchdog('tripal_core', "Error adding custom table '!table_name'.",
+   	      array('!table_name' => $table), WATCHDOG_ERROR);
+         return FALSE;
+      }
+   }
+   if($exists and !$centry){
+   	watchdog('tripal_core', "Could not add custom table '!table_name'. It ".
+   	         "already exists but is not known to Tripal as being a custom table.",
+   	   array('!table_name' => $table), WATCHDOG_WARNING);
+   	   return FALSE;
+   }
+   if($exists and $centry){
+      // drop the table we'll recreate it with the new schema
+      $previous_db = tripal_db_set_active('chado');  // use chado database
+      db_drop_table($ret,$table);
+      db_create_table($ret,$table,$schema);
+      tripal_db_set_active($previous_db);  // now use drupal database
+   }
+
+   // if the table creation was succesful then add an entry
+   // in the tripal_custom_table
+   $record = new stdClass();
+   $record->table_name = $table;
+   $record->schema = serialize($schema);
+   // if an entry already exists then remove it
+   if($centry){
+      $sql = "DELETE FROM {tripal_custom_tables} WHERE table_name = '%s'";
+      db_query($sql,$table);
+   }
+   $success = drupal_write_record('tripal_custom_tables',$record);
+   if(!$success){
+	   watchdog('tripal_core', "Error adding custom table.",
+	      array('!table_name' => $table), WATCHDOG_ERROR);
+      return FALSE;
+   }
+   return $ret;
+}
+
+/**
+ * Retrieves the schema in an array for the specified custom table.
+ *
+ * @param $table
+ *   The name of the table to create.
+ *
+ * @return
+ *   A Drupal-style Schema API array definition of the table. Returns
+ *   FALSE on failure.
+ *
+ * @ingroup tripal_core_api
+ */
+function tripal_get_chado_custom_schema ($table) {
+   $sql = "SELECT schema FROM {tripal_custom_tables} WHERE table_name = '%s'";
+   $custom = db_fetch_object(db_query($sql,$table));
+   if(!$custom){
+      return FALSE;
+   }
+   else {
+      return unserialize($custom->schema);
+   }
+}

+ 22 - 4
tripal_core/tripal_core.install

@@ -28,9 +28,14 @@ function tripal_core_install(){
 * @ingroup tripal_feature
 */
 function tripal_core_update_6000(){
-   // recreate the materialized view
+   // add additional columsn to the tripal_mviews table
    db_add_field($ret, 'tripal_mviews', 'status', array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
    db_add_field($ret, 'tripal_mviews', 'comment', array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+   db_add_field($ret, 'tripal_mviews', 'mv_schema', array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+   db_change_field($ret, 'tripal_mviews', 'mv_table','mv_table',array('type' => 'varchar','length' => 128, 'not null' => FALSE));
+   db_change_field($ret, 'tripal_mviews', 'mv_specs','mv_specs',array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+   db_change_field($ret, 'tripal_mviews', 'indexed','indexed',array('type' => 'text', 'size' => 'normal', 'not null' => FALSE));
+
    
    // create the custom tables table
    $ret = array();
@@ -51,6 +56,18 @@ function tripal_core_update_6000(){
 */
 function tripal_core_schema() {
    $schema = tripal_core_get_schemas();
+   
+   // if this module is already installed and enabled, then we want to provide
+   // the schemas for all of the custom tables.  This will allow Views to 
+   // see the schemas.  We check if the module is installed because during 
+   // installation we don't want to make these custom tables available as we don't
+   // want them created in the Drupal database.  The custom tables go in the 
+   // Chado database.
+   $sql = 'SELECT * FROM {tripal_custom_tables}';
+   $q = db_query($sql);
+   while($custom = db_fetch_object($q)){
+      $schema[$custom->table_name] = unserialize($custom->schema);
+   }
    return $schema;
 }
 /************************************************************************
@@ -100,9 +117,10 @@ function tripal_core_mviews_schema(){
          'mview_id'      => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
          'name'          => array('type' => 'varchar','length' => 255, 'not null' => TRUE),
          'modulename'    => array('type' => 'varchar','length' => 50, 'not null' => TRUE, 'description' => 'The module name that provides the callback for this job'),
-         'mv_table'      => array('type' => 'varchar','length' => 128, 'not null' => TRUE),
-         'mv_specs'      => array('type' => 'text', 'size' => 'normal', 'not null' => TRUE),
-         'indexed'       => array('type' => 'text', 'size' => 'normal', 'not null' => TRUE),
+         'mv_table'      => array('type' => 'varchar','length' => 128, 'not null' => FALSE),
+         'mv_specs'      => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
+         'mv_schema'     => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
+         'indexed'       => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
          'query'         => array('type' => 'text', 'size' => 'normal', 'not null' => TRUE),
          'special_index' => array('type' => 'text', 'size' => 'normal', 'not null' => FALSE),
          'last_update'   => array('type' => 'int', 'not null' => FALSE, 'description' => 'UNIX integer time'),

+ 1 - 2
tripal_core/tripal_core.module

@@ -133,9 +133,8 @@ function tripal_core_menu() {
      'type' => MENU_CALLBACK,
    );
  
-
+   
    // Materialized Views 
-
    $items['admin/tripal/mviews'] = array(
      'title' => 'MViews',
      'description' => 'Materialized views are used to improve speed of large or complex queries.',

+ 31 - 7
tripal_feature/tripal_feature.admin.inc

@@ -125,7 +125,7 @@ function tripal_feature_module_description_page() {
                visitors.    This browser can be toggled on or off using the 
                <a href="'.url('admin/tripal/tripal_feature/configuration').'">Feature Configuration page</a></p></li>
  
-              <li><p><b>Feature Summary:</b>  The feature summary is a pie chart that indicates the types and quantities
+              <li><p><b>Feature Summary Report:</b>  The feature summary report is a pie chart that indicates the types and quantities
               of feature types (Sequence Ontology terms) that are loaded in the database. It appears on the organism 
               page.  The summary can be toggled on or off using the 
               <a href="'.url('admin/tripal/tripal_feature/configuration').'">Feature Configuration page</a></p></li>             
@@ -225,7 +225,9 @@ function tripal_feature_admin () {
 
       $form['browser'] = array(
          '#type' => 'fieldset',
-         '#title' => t('Feature Browser')
+         '#title' => t('Feature Browser'),
+         '#collapsible' => 1,
+         '#collapsed' => 1 ,
       );
       $allowedoptions1  = array (
         'show_feature_browser' => "Show the feature browser on the organism page. The browser loads when page loads. This may be slow for large sites.",
@@ -286,7 +288,9 @@ function tripal_feature_admin () {
 
       $form['feature_edit'] = array(
          '#type' => 'fieldset',
-         '#title' => t('Feature Editing')
+         '#title' => t('Feature Editing'),
+         '#collapsible' => 1,
+         '#collapsed' => 1 ,
       );
 
       $form['feature_edit']['browser_desc'] = array(
@@ -311,7 +315,9 @@ function tripal_feature_admin () {
 
       $form['summary'] = array(
          '#type' => 'fieldset',
-         '#title' => t('Feature Summary')
+         '#title' => t('Feature Summary Report'),
+         '#collapsible' => 1,
+         '#collapsed' => 1 ,
       );
       $allowedoptions2 ['show_feature_summary'] = "Show the feature summary on the organism page. The summary loads when page loads.";
       $allowedoptions2 ['hide_feature_summary'] = "Hide the feature summary on the organism page. Disables the feature summary.";
@@ -324,6 +330,17 @@ function tripal_feature_admin () {
          '#options' => $allowedoptions2,
          '#default_value'=>variable_get('tripal_feature_summary_setting', 'show_feature_summary'),
       );
+      $form['summary']['feature_mapping'] = array(
+         '#title' => 'Map feature types',
+         '#description' => t('You may specify which Sequence Ontology (SO) terms to show in the '.
+            'feature summary report by listing them in the following text area.   Enter one per line. '.
+            'If left blank, all SO terms for all features will be shown in the report. Only those terms '.
+            'listed below will be shown in the report. Terms will appear in the report in the same order listed. To rename a '.
+            'SO term to be more human readable form, use an \'=\' sign after the SO term (e.g. \'polypeptide = Protein\')'),
+         '#type' => 'textarea',
+         '#rows' => 15,
+         '#default_value'=>variable_get('tripal_feature_summary_report_mapping', ''),
+      );
       $form['summary']['set_summary_button'] = array(
          '#type' => 'submit',
          '#value' => t('Set Summary'),
@@ -396,6 +413,7 @@ function tripal_feature_admin_validate($form, &$form_state) {
 
       case t('Set Summary') :
          variable_set('tripal_feature_summary_setting',$form_state['values']['feature_summary']);
+         variable_set('tripal_feature_summary_report_mapping',$form_state['values']['feature_mapping']);
          break;
 
       case t('Set Feature URLs') :
@@ -413,7 +431,9 @@ function tripal_feature_admin_validate($form, &$form_state) {
 function get_tripal_feature_admin_form_cleanup_set(&$form) {
    $form['cleanup'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Clean Up')
+      '#title' => t('Clean Up'),
+      '#collapsible' => 1,
+      '#collapsed' => 1 ,
    );
    $form['cleanup']['description'] = array(
        '#type' => 'item',
@@ -443,7 +463,9 @@ function get_tripal_feature_admin_form_cleanup_set(&$form) {
 function get_tripal_feature_admin_form_reindex_set(&$form) {
    $form['reindex'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Index/Reindex')
+      '#title' => t('Index/Reindex'),
+      '#collapsible' => 1,
+      '#collapsed' => 1 ,
    );
    $form['reindex']['description'] = array(
        '#type' => 'item',
@@ -471,7 +493,9 @@ function get_tripal_feature_admin_form_taxonomy_set (&$form) {
 
    $form['taxonomy'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Set Taxonomy')
+      '#title' => t('Set Taxonomy'),
+      '#collapsible' => 1,
+      '#collapsed' => 1 ,
    );
 
    $form['taxonomy']['description'] = array(

+ 81 - 16
tripal_feature/tripal_feature.module

@@ -1342,6 +1342,41 @@ function tripal_feature_load_organism_feature_counts($organism){
    if(strcmp($show_counts,'show_feature_summary')!=0){
       return array ('enabled' => false );
    }
+   
+
+   $args = array();
+   $names = array();
+   $order = array();
+   
+   // 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.
+   $is_custom = 0;
+   $temp = rtrim(variable_get('tripal_feature_summary_report_mapping', ''));
+   $where = '';
+   if($temp){
+      $is_custom = 1;
+      $temp = explode("\n",$temp);
+      foreach ($temp as $key => $value){
+         // separate the key value pairs
+         $temp2 = explode("=",$value);
+         $feature_type = rtrim($temp2[0]);
+         $args[] = $feature_type;
+         $order[] = $feature_type;
+         // if a new name is provided then use that otherwise just
+         // use the feature type
+         if(count($temp2) == 2){
+            $names[] = rtrim($temp2[1]);
+         } else {
+            $names[] = $feature_type;
+         }
+         $where .= "OFC.feature_type = '%s' OR \n";
+      }
+      if($where){
+         $where = substr($where,0,-5);  # remove OR from the end
+         $where = "($where) AND";
+      }
+   }
 
    // get the feature counts.  This is dependent on a materialized view
    // installed with the organism module
@@ -1349,19 +1384,32 @@ function tripal_feature_load_organism_feature_counts($organism){
       SELECT OFC.num_features,OFC.feature_type,CVT.definition
       FROM {organism_feature_count} OFC
         INNER JOIN {cvterm} CVT on OFC.cvterm_id = CVT.cvterm_id
-      WHERE organism_id = %d 
+      WHERE $where organism_id = %d
       ORDER BY num_features desc
    ";
+   $args[] = $organism->organism_id;
    $previous_db = tripal_db_set_active('chado');  // use chado database
-   $org_features = db_query($sql,$organism->organism_id);
+   $org_features = db_query($sql,$args);
    tripal_db_set_active($previous_db);  // now use drupal database
-
-   $i=0;
+   
+   // iterate through the types 
    $types = array();
    while($type = db_fetch_object($org_features)){
-      $types[$i++] = $type;
+      $types[$type->feature_type] = $type;      
+      // if we don't have an order this means we didn't go through the loop
+      // above to set the names, so do that now
+      if(!$is_custom){
+         $names[] = $type->feature_type;
+         $order[] = $type->feature_type;
+      }
    }
-   return array ( 'types' => $types, 'enabled' => true );
+
+   # now reorder the types
+   $ordered_types = array();
+   foreach ($order as $type){
+      $ordered_types[] = $types[$type];
+   }
+   return array ( 'types' => $ordered_types, 'names' => $names, 'enabled' => true );
 }
 /**
  * 
@@ -1822,20 +1870,37 @@ function tripal_feature_preprocess_tripal_analysis_feature_browser(&$variables){
  */
 function tripal_feature_cv_chart($chart_id){
 
-  // The CV module will create the JSON array necessary for buillding a
-  // pie chart using jgChart and Google Charts.  We have to pass to it
-  // a table that contains count information, tell it which column 
-  // contains the cvterm_id and provide a filter for getting the
-  // results we want from the table.
-  $organism_id = preg_replace("/^tripal_feature_cv_chart_(\d+)$/","$1",$chart_id);
-  $options = array(
+   // we only want the chart to show feature types setup by the admin
+   $temp = rtrim(variable_get('tripal_feature_summary_report_mapping', ''));
+   $where = '';
+   if($temp){
+      $temp = explode("\n",$temp);
+      foreach ($temp as $key => $value){
+         $temp2 = explode("=",$value);
+         $feature_type = rtrim($temp2[0]);
+         $where .= "CNT.feature_type = '$feature_type' OR \n";
+      }
+      if($where){
+         $where = substr($where,0,-5);  # remove OR from the end
+         $where = "($where) AND";
+      }
+   }
+
+   $organism_id = preg_replace("/^tripal_feature_cv_chart_(\d+)$/","$1",$chart_id);
+  
+   // The CV module will create the JSON array necessary for buillding a
+   // pie chart using jgChart and Google Charts.  We have to pass to it
+   // a table that contains count information, tell it which column 
+   // contains the cvterm_id and provide a filter for getting the
+   // results we want from the table.   
+   $options = array(
      count_mview      => 'organism_feature_count',
      cvterm_id_column => 'cvterm_id',
      count_column     => 'num_features',
      size             => '550x200',
-     filter           => "CNT.organism_id = $organism_id",
-  );
-  return $options;
+     filter           => "$where CNT.organism_id = $organism_id",
+   );
+   return $options;
 }
 
 /**

+ 22 - 10
tripal_views/tripal_views.views.inc

@@ -409,7 +409,7 @@ function tripal_views_add_node_ids_to_view (&$view) {
 
 function tripal_views_views_data(){   
   
-   // Define Global Fields -------------
+   // Define Global Fields 
    // Filter handler that lets the admin say: 
    // "Show no results until they enter search parameters"
    $data['views']['search_results'] = array(
@@ -442,7 +442,7 @@ function tripal_views_views_data(){
       $type_prefix = '';
 
       // populate the base table name and fields.  If an $mview_id is given
-      // the get the materialized view info, otherwise get the Chado table info
+      // then get the materialized view info, otherwise get the Chado table info
       if($mview_id){
          $type_prefix = 'MView';
          // get the base table name from the materialized view
@@ -475,10 +475,25 @@ function tripal_views_views_data(){
       else {
          $type_prefix = 'Chado Table';
          $base_table = $tvi_row->table_name;
+         // The chado table could be a regular Chado table or a custom table
+         // in the chado database.  Therefore we'll check both
          $table_desc = module_invoke_all('chado_'.$base_table.'_schema');
+         if(!$table_desc){            
+            $table_desc = tripal_get_chado_custom_schema($base_table);
+         }
          $fields = $table_desc['fields'];
          foreach($fields as $column => $attrs){
-            $base_fields[] = $column;
+            $base_fields[$column] = array(
+              'column_name' => $column,
+              'type' => $attrs['type'],
+            );
+         }
+         // get the field name and descriptions
+         $sql = "SELECT * FROM {tripal_views_field} WHERE setup_id=%d";
+         $query = db_query($sql, $setup_id);
+         while ($field = db_fetch_object($query)) {
+           $base_fields[$field->column_name]['name'] = $field->name;
+           $base_fields[$field->column_name]['help'] = $field->description;
          }
       }
 
@@ -489,7 +504,6 @@ function tripal_views_views_data(){
         'title' => "$type_prefix: $tvi_row->name",
         'help'  => $tvi_row->comment,
       );
-
       // first add the fields
       foreach ($base_fields as $column_name => $base_field){
         $data[$base_table][$column_name] = array(
@@ -499,7 +513,8 @@ function tripal_views_views_data(){
               'click sortable' => TRUE,
            ),
         );
-
+        
+        
         // now add the handlers
         $sql = "SELECT * FROM {tripal_views_handlers} WHERE setup_id = %d AND column_name = '%s'";
         $handlers = db_query($sql,$setup_id,$column_name);
@@ -525,9 +540,7 @@ function tripal_views_views_data(){
         // check to see if the join table is one that correlates with Drupal nodes
         // if so, there will be a chado_<table_name> table in the Drupal database
         // if there is, then we need to add the linking join information
-        $sql = "SELECT tablename FROM pg_tables WHERE tablename = 'chado_$left_table'";
-        if(db_fetch_object(db_query($sql))){
-
+        if(db_table_exists("chado_$left_table")){
            // join the mview to the linker table
            $data[$base_table]['table']['join']["chado_$left_table"] = array(
              'left_field' => $left_field,
@@ -575,8 +588,7 @@ function tripal_views_views_data_alter(&$data) {
         // if there is, then we need to add the linking join information.  We did
         // this step in the hook_views_data function above, but now we need 
         // to add the reciprical joins
-        $sql = "SELECT tablename FROM pg_tables WHERE tablename = '%s'";
-        if(db_fetch_object(db_query($sql,"chado_$left_table"))){
+        if(db_table_exists("chado_$left_table")){
 
            // join the linker table to the mview
            if(array_key_exists("chado_$left_table",$data)){

+ 54 - 33
tripal_views/tripal_views_integration.inc

@@ -65,7 +65,7 @@ function tripal_views_description_page() {
  */
 function tripal_views_integration_setup_list(){
 
-   $header = array('', 'Drupal Views Type Name', 'Table Name', 'Is Mview', 'Priority', 'Comment','');
+   $header = array('', 'Drupal Views Type Name', 'Table Name', 'Legacy Mview', 'Priority', 'Comment','');
    $rows = array();
 
    // get the list of materialized views
@@ -185,16 +185,34 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
                        'and you can specify other tables to join with and handlers.',
    );
 
+  // build the form element for the Chado tables
+  $chado_tables = tripal_core_get_chado_tables();
+  $chado_tables = array_merge(array('Select',), $chado_tables);
+  $form['base_table_type']['table_name'] = array(
+    '#title' => t('Chado/Custom Table'),
+    '#type' => 'select',
+    '#options' => $chado_tables,
+    '#description' => t('Tables from Chado, custom tables and materialized view tables (non-legacy MViews) can be selected for integration.'),
+    '#default_value' => (!$setup_obj->mview_id) ? $setup_obj->table_name : '',
+    '#ahah' => array(
+       'path' => ahah_helper_path(array('view_setup_table')),
+       'wrapper' => 'table-rows-div',
+       'effect' => 'fade',
+       'event' => 'change',
+       'method' => 'replace',
+    ),
+  );
+
 
    // build the form element that lists the materialized views
-   $query = db_query("SELECT mview_id,name FROM {tripal_mviews} ORDER BY name");
+   $query = db_query("SELECT mview_id,name FROM {tripal_mviews} WHERE mv_schema is NULL or mv_schema = '' ORDER BY name");
    $mview_tables = array();
    $mview_tables['0'] = 'Select';
    while ($mview = db_fetch_object($query)){
      $mview_tables[$mview->mview_id] = $mview->name;
    }
    $form['base_table_type']['mview_id'] = array(
-      '#title' => t('Materialized View'),
+      '#title' => t('Legacy Materialized View'),
       '#type' => 'select',
       '#options' => $mview_tables,
       '#description' => 'Which materialized view to use.',
@@ -208,24 +226,6 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
       ),
   );
 
-  // build the form element for the Chado tables
-  $chado_tables = tripal_core_get_chado_tables();
-  $chado_tables = array_merge(array('Select',), $chado_tables);
-  $form['base_table_type']['table_name'] = array(
-    '#title' => t('Chado Table'),
-    '#type' => 'select',
-    '#options' => $chado_tables,
-    '#description' => 'Which Chado table to use.',
-    '#default_value' => (!$setup_obj->mview_id) ? $setup_obj->table_name : '',
-    '#ahah' => array(
-       'path' => ahah_helper_path(array('view_setup_table')),
-       'wrapper' => 'table-rows-div',
-       'effect' => 'fade',
-       'event' => 'change',
-       'method' => 'replace',
-    ),
-  );
-
   $form['views_type'] = array(
      '#type' => 'fieldset',
      '#title' => 'View Type',
@@ -304,12 +304,23 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
        $columns = explode(",",$mview->mv_specs);
     } else {
        $table_desc = module_invoke_all('chado_'.$table_name.'_schema');
-       $fields = $table_desc['fields'];
-       // iterate through the columns and build the format
-       // compatible with the code below. The column name is first followed
-       // by the type with a separating space
-       foreach($fields as $column => $attrs){
-          $columns[] = "$column ".$attrs['type'];
+       if($table_desc){
+          $fields = $table_desc['fields'];
+          // iterate through the columns and build the format
+          // compatible with the code below. The column name is first followed
+          // by the type with a separating space
+          foreach($fields as $column => $attrs){
+             $columns[] = "$column ".$attrs['type'];
+          }
+       }
+       
+       // now do the same for the custom tables
+       $table_desc = tripal_get_chado_custom_schema ($table_name);
+       if($table_desc){
+          $fields = $table_desc['fields'];
+          foreach($fields as $column => $attrs){
+             $columns[] = "$column ".$attrs['type'];
+          }
        }
     }
 
@@ -461,7 +472,12 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
       
       $columns = array();
       if($default_join_table){
+        // get the table description in the typical way and if it returns 
+        // nothing then get the custom table description
         $table_desc = module_invoke_all('chado_'.$default_join_table.'_schema');
+        if(!$table_desc){
+           $table_desc = tripal_get_chado_custom_schema ($default_join_table);
+        }
         foreach ($table_desc['fields'] as $column => $def){
            $columns[$column] = $column;
         }
@@ -513,7 +529,7 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
             if($column_type == 'integer' or $column_type == 'int' or $column_type == 'serial'){
                $default_field_handler = 'chado_views_handler_field_numeric';
             }
-            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text'){
+            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text' or $column_type == 'varchar'){
                $default_field_handler = 'chado_views_handler_field';
             }
             elseif($column_type == 'boolean'){
@@ -548,7 +564,7 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
             if($column_type == 'integer' or $column_type == 'int' or $column_type == 'serial'){
                $default_filter_handler = 'chado_views_handler_filter_numeric';
             }
-            elseif(preg_match("/^character varying/",$column_type) or $column_type == 'char' or $column_type == 'text'){
+            elseif(preg_match("/^character varying/",$column_type) or $column_type == 'char' or $column_type == 'text' or $column_type == 'varchar'){
                $default_filter_handler = 'chado_views_handler_filter_string';
             }
             elseif($column_type == 'boolean'){
@@ -582,7 +598,7 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
             if($column_type == 'integer' or $column_type == 'int' or $column_type == 'serial'){
                $default_sort_handler = 'chado_views_handler_sort';
             }
-            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text'){
+            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text' or $column_type == 'varchar'){
                $default_sort_handler = 'chado_views_handler_sort';
             }
             elseif($column_type == 'boolean'){
@@ -616,7 +632,7 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
             if($column_type == 'integer' or $column_type == 'int' or $column_type == 'serial'){
                $default_argument_handler = 'views_handler_argument_numeric';
             }
-            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text'){
+            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text' or $column_type == 'varchar'){
                $default_argument_handler = 'views_handler_argument_string';
             }
             elseif($column_type == 'boolean'){
@@ -650,7 +666,7 @@ function tripal_views_integration_form(&$form_state, $setup_id = NULL){
             if($column_type == 'integer' or $column_type == 'int' or $column_type == 'serial'){
                $default_relationship_handler = 'views_handler_relationship';
             }
-            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text'){
+            elseif(preg_match("/character varying/",$column_type) or $column_type == 'char' or $column_type == 'text' or $column_type == 'varchar'){
                $default_relationship_handler = 'views_handler_relationship';
             }
             elseif($column_type == 'boolean'){
@@ -831,9 +847,14 @@ function tripal_views_integration_form_submit($form, &$form_state){
       $left_column = $form_state['values']["fields_join_column_$table_id-$i"];
 
       if($left_column){
+         if($mview_id){
+            $base_table = $mview->mv_table;
+         } else {
+            $base_table = $table_name;
+         }
          $view_join_record = array(
            'setup_id' => $tripal_views_record['setup_id'],
-           'base_table' => $mview->mv_table,
+           'base_table' => $base_table,
            'base_field' => $key,
            'left_table' => $left_table,
            'left_field' => $left_column,

+ 17 - 8
tripal_views/views/handlers/views_handler_filter_chado_select_string.inc

@@ -35,6 +35,14 @@ class views_handler_filter_chado_select_string extends views_handler_filter_stri
       '#description' => t('Adds --Any-- to the available options.'),
       '#default_value' => (isset($this->options['optional'])) ? $this->options['optional'] : TRUE,
     );
+ 
+    $form['max_length'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Max Width'),
+      '#description' => t('Specify the maximum width of the select box'),
+      '#default_value' => (isset($this->options['max_length'])) ? $this->options['max_length'] : 40,
+
+    );
     
   }
   
@@ -57,14 +65,15 @@ class views_handler_filter_chado_select_string extends views_handler_filter_stri
         //$options['<select '.$this->table.'>'] = '--None--';
         $options['All'] = '--Any--';
       }
-      $results = tripal_core_chado_select(
-        $this->table,
-        array($this->field),
-        array(),
-        array('order_by' => array($this->field => 'ASC'))
-      );
-      $max_length = 40;
-      foreach ($results as $r) {
+      $sql = "SELECT $this->field FROM $this->table ORDER BY $this->field ASC";
+      $previous_db = tripal_db_set_active('chado');  // use chado database
+      $results = db_query($sql);
+      tripal_db_set_active($previous_db);  // now use drupal database 
+      $max_length = $this->options['max_length'];
+      if(!$max_length){
+         $max_length = 40;
+      }
+      while($r = db_fetch_object($results)){
         if (strlen($r->{$this->field}) > $max_length) {
           $options[$r->{$this->field}] = substr($r->{$this->field},0,$max_length) . '...';
         } else {