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)); // if the user changed the table name, we want to drop the old one and force // creation of the new one. if ($custom_table->table_name != $table_name) { chado_query("DROP TABLE %s", $custom_table->table_name); $skip_creation = 0; // we want to create the table } // if skip creation is not set, then 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 if it already * exists. This is useful if the table was already created through another * means and you simply want to make Tripal aware of the table schema. If the * table does not exist it will be created. * * @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 = 1) { $ret = array(); // see if the table entry already exists in the tripal_custom_tables table. $sql = "SELECT * FROM {tripal_custom_tables} WHERE table_name = '%s'"; $centry = db_fetch_object(db_query($sql, $table)); // check to see if the table already exists in the chado schema $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 the table does not exist then create it 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 the table exists in Chado and in our custom table and // skip creation is turned off then drop and re-create the table if ($exists and is_object($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 %table_name.", array('%table_name' => $table), WATCHDOG_ERROR); drupal_set_message(t("Could not add custom table %table_name. Please check the schema array.", array('%table_name' => $table)), 'error'); return FALSE; } // now add any foreign key constraints if(!$skip_creation and array_key_exists('foreign keys', $schema)){ $fkeys = $schema['foreign keys']; foreach ($fkeys as $fktable => $fkdetails) { $relations = $fkdetails['columns']; foreach ($relations as $left => $right) { $sql = "ALTER TABLE $table ADD CONSTRAINT " . $table . "_" . $left . "_fkey FOREIGN KEY ($left) REFERENCES $fktable ($right) " . "ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED"; if(!chado_query($sql)){ watchdog('tripal_core', "Error, could not add foreign key contraint to custom table.", array('!table_name' => $table), WATCHDOG_ERROR); drupal_set_message(t("Could not add foreign key contraint to table %table_name. Please check the schema array and the report log for errors.", array('%table_name' => $table)), 'error'); return FALSE; } } } } return TRUE; } /** * 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 .= "
" . t("Return to list of custom tables") . "
"; $output .= "Details for $custom_table->table_name:
"; $output .= "| Table Name | ". "$custom_table->table_name | ". "
|---|---|
| Table Field Definitions | ". "" . var_export(unserialize($custom_table->schema),1) . " | ".
"
| Actions | ". "". " Edit, ". " Delete |
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',
),
),
),
)
",
);
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'];
$force_drop = $form_state['values']['force_drop'];
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 = preg_match('/^\s*array/', $schema);
if (!$success) {
form_set_error($form_state['values']['schema'],
t("The schema array should begin with the word 'array'."));
}
else {
$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'"));
}
// check to see if the table name matches an existing table
// if this is an add
if ($action == 'Add') {
$previous_db = tripal_db_set_active('chado');
$exists = db_table_exists($schema_array['table']);
tripal_db_set_active($previous_db);
if ($exists) {
form_set_error($form_state['values']['schema'],
t("The table name already exists, please choose a different name."));
}
}
if ($action == 'Edit') {
// see if the table name has changed. If so, then check to make sure
// it doesn't already exists. We don't want to drop a table we didn't mean to
$sql = "SELECT * FROM {tripal_custom_tables} WHERE table_id = %d";
$ct = db_fetch_object(db_query($sql, $table_id));
if ($ct->table_name != $schema_array['table']) {
$previous_db = tripal_db_set_active('chado');
$exists = db_table_exists($schema_array['table']);
tripal_db_set_active($previous_db);
if ($exists) {
form_set_error($form_state['values']['schema'],
t("The table name already exists, please choose a different name."));
}
}
}
}
}
}
/**
* 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'];
$force_drop = $form_state['values']['force_drop'];
$skip_creation = 1;
if ($force_drop) {
$skip_creation = 0;
}
// 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");
}
}