class will do the trick.
*/
/*
function schema_init() {
schema_require();
}
function schema_require() {
static $done = 0;
if ($done++) {
return;
}
// Load all our module 'on behalfs' so they will be available for
// any module (including this one) that needs them.
// TODO: What precisely is the purpose of this? To allow other
$path = drupal_get_path('module', 'schema');
$files = drupal_system_listing('/schema_.*\.inc$/', $path . '/modules', 'name', 0);
foreach ($files as $file) {
// The filename format is very specific. It must be schema_MODULENAME.inc
$module = substr_replace($file->name, '', 0, 7);
require_once("./$file->filename");
}
}
*/
/**
* Implement of hook_permission().
*/
function schema_permission() {
return array(
'administer schema' => array(
'title' => t('Administer schema module'),
),
);
}
/**
* Implement of hook_menu().
* Define menu items and page callbacks.
* admin/structure/schema calls local task(default): schema_compare()
* admin/structure/schema/compare calls local task: schema_compare()
* admin/structure/schema/describe calls local task: schema_describe()
* admin/structure/schema/inspect calls local task: schema_inspect()
* admin/structure/schema/sql calls local task: schema_sql()
* admin/structure/schema/show calls local task: schema_show()
*/
function schema_menu() {
$items['admin/structure/schema'] = array(
'title' => 'Schema',
'description' => 'Manage the database schema for this system.',
'page callback' => 'drupal_get_form',
'page arguments' => array('schema_compare'),
'access arguments' => array('administer schema'),
);
$items['admin/structure/schema/compare'] = array(
'title' => 'Compare',
'type' => MENU_DEFAULT_LOCAL_TASK,
'page callback' => 'drupal_get_form',
'page arguments' => array('schema_compare'),
'weight' => -10,
'access arguments' => array('administer schema'),
);
$items['admin/structure/schema/describe'] = array(
'title' => 'Describe',
'type' => MENU_LOCAL_TASK,
'page callback' => 'drupal_get_form',
'page arguments' => array('schema_describe'),
'weight' => -8,
'access arguments' => array('administer schema'),
);
$items['admin/structure/schema/inspect'] = array(
'title' => 'Inspect',
'type' => MENU_LOCAL_TASK,
'page callback' => 'drupal_get_form',
'page arguments' => array('schema_inspect'),
'weight' => -6,
'access arguments' => array('administer schema'),
);
$items['admin/structure/schema/sql'] = array(
'title' => 'SQL',
'type' => MENU_LOCAL_TASK,
'page callback' => 'schema_sql',
'weight' => -4,
'access arguments' => array('administer schema'),
);
// This can't work unless we rename the functions in database.*.inc.
global $_schema_engines;
if (FALSE && isset($_schema_engines) && is_array($_schema_engines)) {
foreach ($_schema_engines as $engine) {
$items['admin/structure/schema/sql/' . $engine] = array(
'title' => $engine,
'type' => ($engine == db_driver() ? MENU_DEFAULT_LOCAL_TASK :
MENU_LOCAL_TASK),
'page callback' => 'schema_sql',
'callback arguments' => $engine,
'access arguments' => array('administer schema'),
);
}
}
$items['admin/structure/schema/show'] = array(
'title' => 'Show',
'type' => MENU_LOCAL_TASK,
'page callback' => 'schema_show',
'weight' => -2,
'access arguments' => array('administer schema'),
);
$items['admin/structure/schema/settings'] = array(
'title' => 'Settings',
'type' => MENU_LOCAL_TASK,
'page callback' => 'drupal_get_form',
'page arguments' => array('schema_settings'),
'weight' => 0,
'access arguments' => array('administer schema'),
);
return $items;
}
function _schema_process_description($desc) {
return preg_replace('@{([a-z_]+)}@i', '$1', $desc);
}
/**
* "Compare" menu callback.
* This function just massages the data returned by
* schema_compare_schemas() into HTML.
*/
function schema_compare() {
$form = array();
$form['description'] = array(
'#prefix' => '',
'#markup' => t('This page compares the live database as it currently exists against
the combination of all schema information provided by all enabled modules'),
'#suffix' => '
',
);
$states = array(
'same' => t('Match'),
'different' => t('Mismatch'),
'missing' => t('Missing'),
);
$descs = array(
'same' => 'Tables for which the schema and database agree.',
'different' => 'Tables for which the schema and database are different.',
'missing' => 'Tables in the schema that are not present in the database.',
);
$schema = drupal_get_schema(NULL, TRUE);
$info = schema_compare_schemas($schema);
// The info array is keyed by state (same/different/missing/extra/warn). For missing,
// the value is a simple array of table names. For warn, it is a simple array of warnings.
// Get those out of the way first
$warnings = $info['warn'];
foreach ($warnings as $message) {
drupal_set_message($message, 'warning');
}
unset($info['warn']);
$form['extra'] = array(
'#type' => 'fieldset',
'#title' => t('Extra (@count)',
array('@count' => count($info['extra']))),
'#description' => t('Tables in the database that are not present in the schema. This
indicates previously installed modules that are disabled but not un-installed or
modules that do not use the Schema API.'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 50, // This goes last
);
$form['extra']['tablelist'] = array(
'#theme' => 'item_list',
'#items' => $info['extra'],
);
unset($info['extra']);
// For the other states, the value is an array keyed by module name. Each value
// in that array is an array keyed by tablename, and each of those values is an
// array containing 'status' (same as the state), an array of reasons, and an array of notes.
$weight = 0;
foreach ($info as $state => $modules) {
// We'll fill in the fieldset title below, once we have the counts
$form[$state] = array(
'#type' => 'fieldset',
'#description' => t($descs[$state]),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => $weight++,
);
$counts[$state] = 0;
foreach ($modules as $module => $tables) {
$counts[$state] += count($tables);
$form[$state][$module] = array(
'#type' => 'fieldset',
'#title' => t($module),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
switch ($state) {
case 'same':
case 'missing':
$form[$state][$module]['tablelist'] = array(
'#theme' => 'item_list',
'#items' => array_keys($tables),
);
break;
case 'different':
$items = array();
foreach ($tables as $name => $stuff) {
$form[$state][$module][$name] = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#title' => $name,
);
$form[$state][$module][$name]['reasons'] = array(
'#theme' => 'item_list',
'#items' => array_merge($tables[$name]['reasons'], $tables[$name]['notes']),
);
}
break;
}
}
}
// Fill in counts in titles
foreach ($states as $state => $description) {
$form[$state]['#title'] = t('@state (@count)',
array('@state' => $states[$state], '@count' => isset($counts[$state]) ? $counts[$state] : 0));
}
return $form;
}
/**
* "Describe" menu callback.
*/
function schema_describe() {
$schema = drupal_get_schema(NULL, TRUE);
ksort($schema);
$row_hdrs = array(t('Name'), t('Type[:Size]'), t('Null?'), t('Default'));
$form = array();
$form['description'] = array(
'#prefix' => '',
'#markup' => "This page describes the Drupal database schema. Click on a table name
to see that table's description and fields. Table names within a table or
field description are hyperlinks to that table's description.",
'#suffix' => '
',
);
$default_table_description = t('TODO: please describe this table!');
$default_field_description = t('TODO: please describe this field!');
foreach ($schema as $t_name => $t_spec) {
$rows = array();
foreach ($t_spec['fields'] as $c_name => $c_spec) {
$row = array();
$row[] = $c_name;
$type = $c_spec['type'];
if (!empty($c_spec['length'])) {
$type .= '(' . $c_spec['length'] . ')';
}
if (!empty($c_spec['scale']) && !empty($c_spec['precision'])) {
$type .= '(' . $c_spec['precision'] . ', ' . $c_spec['scale'] . ' )';
}
if (!empty($c_spec['size']) && $c_spec['size'] != 'normal') {
$type .= ':' . $c_spec['size'];
}
if ($c_spec['type'] == 'int' && !empty($c_spec['unsigned'])) {
$type .= ', unsigned';
}
$row[] = $type;
$row[] = !empty($c_spec['not null']) ? 'NO' : 'YES';
$row[] = isset($c_spec['default']) ? (is_string($c_spec['default']) ? '\'' . $c_spec['default'] . '\'' : $c_spec['default']) : '';
$rows[] = $row;
if (!empty($c_spec['description']) && $c_spec['description'] != $default_field_description) {
$desc = _schema_process_description($c_spec['description']);
$rows[] = array(array('colspan' => count($row_hdrs), 'data' => $desc));
}
else {
drupal_set_message(_schema_process_description(t('Field {!table}.@field has no description.', array('!table' => $t_name, '@field' => $c_name))), 'warning');
}
}
if (empty($t_spec['description']) || $t_spec['description'] == $default_table_description) {
drupal_set_message(_schema_process_description(t('Table {!table} has no description.', array('!table' => $t_name))), 'warning');
}
$form[$t_name] = array(
'#type' => 'fieldset',
'#title' => t('@table (@module module)',
array('@table' => $t_name, '@module' => isset($t_spec['module']) ? $t_spec['module'] : '')),
'#description' => !empty($t_spec['description']) ? _schema_process_description($t_spec['description']) : '',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#attributes' => array('id' => 'table-' . $t_name),
);
$form[$t_name]['content'] = array(
'#theme' => 'table',
'#header' => $row_hdrs,
'#rows' => $rows,
);
}
return $form;
}
/**
* "Inspect" menu callback.
*/
function schema_inspect() {
$form = array();
$form['description'] = array(
'#prefix' => '',
'#markup' => t("This page shows the live database schema as it currently
exists on this system. Known tables are grouped by the module that
defines them; unknown tables are all grouped together.
To implement hook_schema() for a module that has existing tables, copy
the schema structure for those tables directly into the module's
hook_schema() and return \$schema."),
'#suffix' => '
',
);
$mods = module_list();
sort($mods);
$mods = array_flip($mods);
$schema = drupal_get_schema(NULL, TRUE);
$inspect = schema_dbobject()->inspect(variable_get('schema_database_connection', 'default'));
foreach ($inspect as $name => $table) {
$module = isset($schema[$name]['module']) ? $schema[$name]['module'] : 'Unknown';
if (!isset($form[$module])) {
$form[$module] = array(
'#type' => 'fieldset',
'#access' => TRUE,
'#title' => check_plain($module),
'#collapsible' => TRUE,
'#collapsed' => ($module != 'Unknown'),
'#weight' => ($module == 'Unknown' ? 0 : $mods[$module]+1),
);
}
$form[$module][$name] = array(
'#type' => 'markup',
'#markup' => '');
}
return $form;
}
/**
* "SQL" menu callback.
*/
function schema_sql($engine = NULL) {
$schema = drupal_get_schema(NULL, TRUE);
$connection = Database::getConnection();
$sql = '';
foreach ($schema as $name => $table) {
if (substr($name, 0, 1) == '#') {
continue;
}
if ($engine) {
$stmts = call_user_func('schema_' . $engine . '_create_table_sql', $table);
}
else {
$stmts = schema_dbobject()->getCreateTableSql($name, $table);
}
$sql .= implode(";\n", $stmts) . ";\n\n";
}
$output = t('This page shows the CREATE TABLE statements that the Schema API
generates for the selected database engine for each table defined by a
module. It is for debugging purposes.
');
$output .= "";
return $output;
}
/**
* "Show" menu callback.
* Displays drupal schema as php code, so you can reuse it
* as you need.
*/
function schema_show() {
$schema = drupal_get_schema(NULL, TRUE);
$show = var_export($schema, 1);
$output = t('This page displays the Drupal database schema data structure. It is for
debugging purposes.
');
$output .= "";
return $output;
}
function schema_settings($form, &$form_state) {
global $databases;
if (count($databases) > 1) {
$form['schema_database_connection'] = array(
'#type' => 'select',
'#title' => t('Database connection to use'),
'#default_value' => variable_get('schema_database_connection', 'default'),
'#options' => array_combine(array_keys($databases), array_keys($databases)),
'#description' => t('If you use a secondary database other than the default
Drupal database you can select it here and use schema\'s "compare" and
"inspect" functions on that other database.'),
);
}
$form['schema_status_report'] = array(
'#type' => 'checkbox',
'#title' => t('Include schema comparison reports in site status report'),
'#default_value' => variable_get('schema_status_report', TRUE),
'#description' => t('When checked, schema comparison reports are run on
the Administer page, and included in the site status report.'),
);
$form['schema_suppress_type_warnings'] = array(
'#type' => 'checkbox',
'#title' => t('Suppress schema warnings.'),
'#default_value' => variable_get('schema_suppress_type_warnings', FALSE),
'#description' => t('When checked, missing schema type warnings will be suppressed.'),
);
return system_settings_form($form);
}