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"); } }