Parcourir la source

added custom_tables.php

spficklin il y a 12 ans
Parent
commit
b20240b47e
1 fichiers modifiés avec 516 ajouts et 0 suppressions
  1. 516 0
      tripal_core/includes/custom_tables.php

+ 516 - 0
tripal_core/includes/custom_tables.php

@@ -0,0 +1,516 @@
+<?php
+
+/**
+ * @file
+ * Contains functions for the Custom Tables API
+
+ * @defgroup tripal_custom_tables_api Core Module Custom Tables API
+ * @{
+ * Provides an application programming interface (API) to manage custom tables in Chado.
+ * @}
+ * @ingroup tripal_api
+ */
+
+
+/**
+ * Edits a custom table in the chado database. It supports 
+ * using the Drupal Schema API array.
+ *
+ * @param $table_id
+ *   The table_id of the table to edit
+ * @param $table_name
+ *   The name of the custom table
+ * @param $schema
+ *   Use the Schema API array to define the custom table.
+ * @param $skip_creation
+ *   Set as TRUE to skip dropping and re-creation of the table.  This is
+ *   useful if the table was already created through another means and you
+ *   simply want to make Tripal aware of the table schema.
+ *
+ * @ingroup tripal_custom_tables_api
+ */
+function tripal_core_edit_custom_table($table_id, $table_name, $schema, $skip_creation = 0) {
+
+  // Create a new record
+  $record = new stdClass();
+  $record->table_id = $table_id;
+  $record->table_name = $table_name;
+  $record->schema = serialize($schema);
+
+  // get the current custom table record
+  $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_id = %d";
+  $custom_table = db_fetch_object(db_query($sql, $table_id));
+
+  // drop the table from chado if it exists
+  if(!$skip_creation){
+    if (db_table_exists($custom_table->table_name)) {
+      chado_query("DROP TABLE %s", $custom_table->table_name);
+      drupal_set_message(t("Custom Table '%name' dropped", array('%name' => $custom_table->table_name)));
+    }
+  }
+
+  // update the custom table record and re-create the table in Chado
+  if (drupal_write_record('tripal_custom_tables', $record, 'table_id')) {
+
+    // drop the table from chado if it exists
+    if(!$skip_creation){
+      if (db_table_exists($custom_table->table_name)) {
+        chado_query("DROP TABLE %s", $custom_table->table_name);
+        drupal_set_message(t("Custom Table '%name' dropped", array('%name' => $custom_table->table_name)));
+      }
+
+      // re-create the table
+      if (!tripal_core_create_custom_table ($ret, $table_name, $schema)) {
+        drupal_set_message(t("Could not create the custom table. Check Drupal error report logs."));
+      }
+      else {
+        drupal_set_message(t("Custom table '%name' created", array('%name' => $table_name)));
+      }
+    }
+    // TODO: add FK constraints
+  }
+}
+
+/**
+ * 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.
+ * However, 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.  If $skip_creation is set then the table is simply
+ * added to the tripal_custom_tables and no table is created in Chado.
+ *
+ * @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
+ * @param $skip_creation
+ *   Set as TRUE to skip dropping and re-creation of the table.  This is
+ *   useful if the table was already created through another means and you
+ *   simply want to make Tripal aware of the table schema.
+ *
+ * @return
+ *   A database query result resource for the new table, or FALSE if table was not constructed.
+ *
+ * @ingroup tripal_custom_tables_api
+ */
+function tripal_core_create_custom_table(&$ret, $table, $schema, $skip_creation = 0) {
+  $ret = array();
+    
+  // see if the table entry already exists
+  $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_name = '%s'";
+  $centry = db_fetch_object(db_query($sql, $table));
+  
+  // 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.  
+  $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 and !$skip_creation) {
+    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 and !$skip_creation) {
+    // 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
+  }
+
+  // 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;
+}
+
+/**
+ * Retrieve the custom table id given the name
+ *
+ * @param $table_name
+ *   The name of the custom table
+ *
+ * @return
+ *   The unique identifier for the given table
+ *
+ * @ingroup tripal_custom_tables_api
+ */
+function tripal_custom_tables_get_table_id($table_name) {
+  $sql = "SELECT * FROM {tripal_custom_tables} ".
+         "WHERE table_name = '%s'";
+  if (db_table_exists('tripal_custom_tables')) {
+    $custom_table = db_fetch_object(db_query($sql, $table_name));
+    if ($custom_table) {
+      return $custom_table->table_id;
+    }
+  }
+
+  return FALSE;
+}
+
+
+
+/**
+ * A template function which returns markup to display details for the custom table
+ *
+ * @param $table_id
+ *  The unique ID of the custom table
+ *
+ * @ingroup tripal_custom_tables_api
+ */
+function tripal_custom_table_view($table_id) {
+
+  // get this custom_table details
+  $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_id = %d";
+  $custom_table = db_fetch_object(db_query($sql, $table_id));
+
+  // create a table with each row containig stats for
+  // an individual job in the results set.
+  $return_url = url("admin/tripal/custom_tables/");
+  $output .= "<p><a href=\"$return_url\">" . t("Return to list of custom tables") . "</a></p>";
+  $output .= "<br />";
+  $output .= "<p>Details for <b>$custom_table->table_name</b>:</p>";
+  $output .= "<br />";
+  $output .= "<table class=\"border-table\">";
+  if ($custom_table->table_name) {
+    $output .= "  <tr>".
+    "    <th>Table Name</th>".
+    "    <td>$custom_table->table_name</td>".
+    "  </tr>";
+  }
+  if ($custom_table->schema) {
+    $output .= "  <tr>".
+    "    <th>Table Field Definitions</th>".
+    "    <td><pre>" . var_export(unserialize($custom_table->schema),1) . "</pre></td>".
+    "  </tr>";
+  }
+
+  // build the URLs using the url function so we can handle installations where
+  // clean URLs are or are not used
+  $delete_url = url("admin/tripal/custom_tables/action/delete/$custom_table->table_id");
+  $edit_url = url("admin/tripal/custom_tables/edit/$custom_table->table_id");
+  $output .= "<tr><th>Actions</th>".
+            "<td>".
+            "     <a href='$edit_url'>Edit</a>, ".
+            "     <a href='$delete_url'>Delete</a></td></tr>";
+  $output .= "</table>";
+
+  return $output;
+}
+
+/**
+ * A template function to render a listing of all Custom tables
+ *
+ * @ingroup tripal_custom_tables_api
+ */
+function tripal_custom_tables_list() {
+  $header = array('', 'Table Name', 'Description');
+  $rows = array();
+  $custom_tables = db_query("SELECT * FROM {tripal_custom_tables} ORDER BY table_name");
+
+  while ($custom_table = db_fetch_object($custom_tables)) {
+ 
+    $rows[] = array(
+      l(t('View'), "admin/tripal/custom_tables/view/$custom_table->table_id") ." | ".
+      l(t('Edit'), "admin/tripal/custom_tables/edit/$custom_table->table_id") ." | ".
+      $custom_table->table_name,
+      $custom_table->comment,
+      l(t('Delete'), "admin/tripal/custom_tables/action/delete/$custom_table->table_id"),
+    );
+  }
+
+  $rows[] = array(
+    'data' => array(
+      array('data' => l(t('Create a new custom table.'), "admin/tripal/custom_tables/new"),
+        'colspan' => 6),
+    )
+  );
+
+  $page = theme('table', $header, $rows);
+  return $page;
+}
+
+/**
+ * A Form to Create/Edit a Custom table
+ *
+ * @param $form_state
+ *   The current state of the form (Form API)
+ * @param $table_id
+ *   The unique ID of the Custom table to Edit or NULL if creating a new table
+ *
+ * @return
+ *   A form array (Form API)
+ *
+ * @ingroup tripal_core
+ */
+function tripal_custom_tables_form(&$form_state = NULL, $table_id = NULL) {
+
+  if (!$table_id) {
+    $action = 'Add';
+  }
+  else {
+    $action = 'Edit';
+  }
+
+  // get this requested table
+  if (strcmp($action, 'Edit')==0) {
+    $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_id = %d ";
+    $custom_table = db_fetch_object(db_query($sql, $table_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
+    $default_schema = $form_state['values']['schema'];
+    $default_skip = $form_state['values']['skip_creation'];
+
+    if (!$default_table_name) {
+      $default_table = $custom_table->table_name;
+    }
+    if (!$default_schema) {
+      $default_schema = var_export(unserialize($custom_table->schema),1);
+    }
+  }
+
+  // Build the form
+  $form['action'] = array(
+    '#type' => 'value',
+    '#value' => $action
+  );
+
+  $form['table_id'] = array(
+    '#type' => 'value',
+    '#value' => $table_id
+  );
+  
+  $form['instructions']= array(
+    '#type'          => 'markup',
+    '#value'         => t('At times it is necessary to add a custom table to the Chado schema.  
+       These are not offically sanctioned tables but may be necessary for local data requirements.  
+       Avoid creating custom tables when possible as other GMOD tools may not recognize these tables
+       nor the data in them.  Linker tables are often a good candidate for
+       a custom table. For example a table to link stocks and libraries (e.g. library_stock).  If the
+       table already exists it will be dropped and re-added using the definition supplied below. All 
+       data in the table will be lost.  However, If you
+       are certain the schema definition you provide is correct for an existing table, select the checkbox
+       below to skip creation of the table.
+    '),
+  );
+
+  $form['skip_creation']= array(
+    '#type'          => 'checkbox',
+    '#title'         => t('Skip Table Creation'),
+    '#description'   => t('If your table already exists, check this box to prevent it from being dropped and re-created.'),
+    '#default_value' => $default_skip,
+  );
+  $form['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,
+  );
+
+  if ($action == 'Edit') {
+    $value = 'Save';
+  }
+  if ($action == 'Add') {
+    $value = 'Add';
+  }
+  $form['submit'] = array(
+    '#type'         => 'submit',
+    '#value'        => t($value),
+    '#executes_submit_callback' => TRUE,
+  );
+  $form['#redirect'] = 'admin/tripal/custom_tables';
+  
+  $form['example']= array(
+    '#type'          => 'markup',
+    '#value'         => "<br>Example library_stock table: <pre>
+array (
+  'table' => 'library_stock',
+  'fields' => array (
+    'library_stock_id' => array(
+      'type' => serial,
+      'not null' => TRUE,
+    ),
+    'library_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+    ),      
+    'stock_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+    ),
+  ),
+  'primary key' => array(
+    'library_stock_id'
+  ),
+  'unique keys' => array(
+    'library_stock_c1' => array(
+      'library_id',
+      'stock_id'
+    ),
+  ),
+  'foreign keys' => array(
+    'library' => array(
+      'table' => 'library',
+      'columns' => array(
+        'library_id' => 'library_id',
+      ),
+    ),
+    'stock' => array(
+      'table' => 'stock',
+      'columns' => array(
+        'stock_id' => 'stock_id',
+      ),
+    ),
+  ),
+)
+    </pre>",
+  );
+  
+
+  return $form;
+}
+
+/**
+ * Validate the Create/Edit custom table form
+ * Implements hook_form_validate().
+ *
+ * @ingroup tripal_core
+ */
+function tripal_custom_tables_form_validate($form, &$form_state) {
+  $action = $form_state['values']['action'];
+  $table_id = $form_state['values']['table_id'];
+  $schema = $form_state['values']['schema'];
+
+  if (!$schema) {
+    form_set_error($form_state['values']['schema'],
+      t('Schema array field is required.'));
+  }
+
+  // make sure the array is valid
+  $schema_array = array();
+  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 (is_array($schema_array) and !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
+  }
+}
+
+/**
+ * Submit the Create/Edit Custom table form
+ * Implements hook_form_submit().
+ *
+ * @ingroup tripal_core
+ */
+function tripal_custom_tables_form_submit($form, &$form_state) {
+
+  $ret = array();
+  $action = $form_state['values']['action'];
+  $table_id = $form_state['values']['table_id'];
+  $schema = $form_state['values']['schema'];
+  $skip_creation = $form_state['values']['skip_creation'];
+
+  // conver the schema into a PHP array
+  $schema_arr = array();
+  eval("\$schema_arr = $schema;");
+
+  if (strcmp($action, 'Edit') == 0) {
+    tripal_core_edit_custom_table($table_id, $schema_arr['table'], $schema_arr, $skip_creation);
+  }
+  elseif (strcmp($action, 'Add') == 0) {
+    tripal_core_create_custom_table($ret, $schema_arr['table'], $schema_arr, $skip_creation);
+  }
+  else {
+    drupal_set_message(t("No action performed."));
+  }
+
+  return '';
+}
+/**
+ * Does the specified action for the specified custom table
+ *
+ * @param $op
+ *   The action to be taken. Currenly only delete is available
+ * @param $table_id
+ *   The unique ID of the custom table for the action to be performed on
+ * @param $redirect
+ *   TRUE/FALSE depending on whether you want to redirect the user to admin/tripal/custom_tables
+ *
+ * @ingroup tripal_core
+ */
+function tripal_custom_tables_action($op, $table_id, $redirect = FALSE) {
+  global $user;
+
+  $args = array("$table_id");
+  if (!$table_id) {
+    return '';
+  }
+
+  // get this table details
+  $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_id = %d";
+  $custom_table = db_fetch_object(db_query($sql, $table_id));
+
+  if ($op == 'delete') {
+  
+    // remove the entry from the tripal_custom tables table
+    $sql = "DELETE FROM {tripal_custom_tables} ".
+           "WHERE table_id = $table_id";
+    db_query($sql);
+    
+    // drop the table from chado if it exists
+    if (db_table_exists($custom_table->table_name)) {
+      $success = chado_query("DROP TABLE %s", $custom_table->table_name);
+      if($success){
+        drupal_set_message(t("Custom Table '%name' dropped", array('%name' => $custom_table->table_name)));
+      }
+    }
+  }
+
+  // Redirect the user
+  if ($redirect) {
+    drupal_goto("admin/tripal/custom_tables");
+  }
+}