| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: schema.module,v 1.43.2.9 2010/02/01 19:03:18 mikeryan Exp $ 3 4 /** 5 * @file The Schema module provides functionality built on the Schema API. 6 */ 7 global $schema_engines; 8 9 ////////////////////////////////////////////////////////////////////// 10 // Schema print functions 11 ////////////////////////////////////////////////////////////////////// 12 13 /** 14 * Builds a pretty ASCII-formatted version of a $schema array. 15 * 16 * This is nothing more than a specialized variation of var_dump and 17 * similar functions and is used only as a convenience to generate the 18 * PHP for existing database tables (to bootstrap support for modules 19 * that previously used CREATE TABLE explicitly) and for debugging. 20 */ 21 function schema_phpprint($schema) { 22 $out = ''; 23 foreach ($schema as $name => $table) { 24 $out .= schema_phpprint_table($name, $table); 25 } 26 return $out; 27 } 28 29 function schema_phpprint_table($name, $table) { 30 $cols = array(); 31 if (isset($table['fields'])) { 32 foreach ($table['fields'] as $colname => $col) { 33 $cols[] = "'$colname' => ".schema_phpprint_column($col, TRUE); 34 } 35 } 36 $unique = $index = array(); 37 if (isset($table['unique keys'])) { 38 foreach ($table['unique keys'] as $keyname => $key) { 39 $unique[] = "'$keyname' => ".schema_phpprint_key($key); 40 } 41 } 42 if (isset($table['indexes'])) { 43 foreach ($table['indexes'] as $keyname => $key) { 44 $index[] = "'$keyname' => ".schema_phpprint_key($key); 45 } 46 } 47 if ($table['description']) { 48 $description = $table['description']; 49 } 50 else { 51 $description = t('TODO: please describe this table!'); 52 } 53 $out = ''; 54 $out .= "\$schema['".$name."'] = array(\n"; 55 $out .= " 'description' => t('$description'),\n"; 56 $out .= " 'fields' => array(\n "; 57 $out .= implode(",\n ", $cols); 58 $out .= ",\n ),\n"; 59 if (isset($table['primary key'])) { 60 $out .= " 'primary key' => array('".implode("', '", $table['primary key'])."'),\n"; 61 } 62 if (count($unique) > 0) { 63 $out .= " 'unique keys' => array(\n "; 64 $out .= implode(",\n ", $unique); 65 $out .= "\n ),\n"; 66 } 67 if (count($index) > 0) { 68 $out .= " 'indexes' => array(\n "; 69 $out .= implode(",\n ", $index); 70 $out .= ",\n ),\n"; 71 } 72 $out .= ");\n"; 73 return $out; 74 } 75 76 function schema_phpprint_column($col, $multiline=FALSE) { 77 $attrs = array(); 78 if ($col['description']) { 79 $description = $col['description']; 80 } 81 else { 82 $description = t('TODO: please describe this field!'); 83 } 84 unset($col['description']); 85 $attrs[] = "'description' => t('$description')"; 86 if ($col['type'] == 'varchar' || $col['size'] == 'normal') { 87 unset($col['size']); 88 } 89 foreach (array('type', 'unsigned', 'size', 'length', 'not null', 'default') as $attr) { 90 if (isset($col[$attr])) { 91 if (is_string($col[$attr])) { 92 $attrs[] = "'$attr' => '$col[$attr]'"; 93 } 94 else if (is_bool($col[$attr])) { 95 $attrs[] = "'$attr' => ".($col[$attr] ? 'TRUE' : 'FALSE'); 96 } 97 else { 98 $attrs[] = "'$attr' => $col[$attr]"; 99 } 100 unset($col[$attr]); 101 } 102 } 103 foreach (array_keys($col) as $attr) { 104 if (is_string($col[$attr])) { 105 $attrs[] = "'$attr' => '$col[$attr]'"; 106 } else { 107 $attrs[] = "'$attr' => $col[$attr]"; 108 } 109 } 110 if ($multiline) { 111 return "array(\n ".implode(",\n ", $attrs).",\n )"; 112 } 113 return "array(".implode(', ', $attrs).")"; 114 } 115 116 function schema_phpprint_key($keys) { 117 $ret = array(); 118 foreach ($keys as $key) { 119 if (is_array($key)) { 120 $ret[] = "array('$key[0]', $key[1])"; 121 } else { 122 $ret[] = "'$key'"; 123 } 124 } 125 return "array(".implode(", ", $ret).")"; 126 } 127 128 ////////////////////////////////////////////////////////////////////// 129 // Schema comparison functions 130 ////////////////////////////////////////////////////////////////////// 131 132 function schema_unprefix_table($name) { 133 global $db_prefix; 134 static $_db_prefix; 135 136 if (is_array($db_prefix)) { 137 if (!isset($_db_prefix)) { 138 foreach ($db_prefix as $key => $val) { 139 $_db_prefix[$val.$key] = $key; 140 } 141 } 142 if (isset($_db_prefix[$name])) { 143 return $_db_prefix[$name]; 144 } else if (!empty($db_prefix['default']) && preg_match('@^'.$db_prefix['default'].'(.*)@', $name, $m)) { 145 return $m[1]; 146 } else { 147 // On pgsql, key and index names are also prefixed 148 // (e.g. 'prefix_blocks_roles_rid_idx'). 149 foreach ($db_prefix as $key => $val) { 150 if (($key != 'default' && preg_match('@^'.$val.'('.$key.'.*)@', $name, $m)) || 151 ($key == 'default' && preg_match('@^'.$val.'(.*)@', $name, $m))) { 152 return $m[1]; 153 } 154 } 155 return $name; 156 } 157 } else if (!empty($db_prefix) && preg_match('@^'.$db_prefix.'(.*)@', $name, $m)) { 158 return $m[1]; 159 } 160 return $name; 161 } 162 163 function schema_invoke($op) { 164 $db_name = variable_get('schema_database_connection', 'default'); 165 if($db_name !== 'default'){ 166 db_set_active($db_name); 167 } 168 // We could be called by other modules (notably Table Wizard or Migrate) in an update 169 // function, which does not call hook_init(). So, make sure we get our include files included... 170 schema_require(); 171 172 global $db_type; 173 $function = 'schema_'.$db_type.'_'.$op; 174 $args = func_get_args(); 175 array_shift($args); 176 $return = call_user_func_array($function, $args); 177 if($db_name !== 'default'){ 178 db_set_active('default'); 179 } 180 return $return; 181 } 182 183 function schema_engine_invoke($engine, $op) { 184 global $db_type; 185 if (!isset($engine)) { 186 $engine = $db_type; 187 } 188 $function = 'schema_'.$engine.'_'.$op; 189 $args = func_get_args(); 190 array_shift($args); 191 return call_user_func_array($function, $args); 192 } 193 194 /** 195 * Converts a column's Schema type into an engine-specific data type. 196 */ 197 function schema_engine_type($col, $table, $field, $engine = NULL) { 198 $map = schema_engine_invoke($engine, 'engine_type_map'); 199 $size = (isset($col['size']) ? $col['size'] : 'normal'); 200 $type = $col['type'].':'.$size; 201 if (isset($map[$type])) { 202 return $map[$type]; 203 } else { 204 drupal_set_message(t('%table.%field: no %engine type for Schema type %type.', 205 array('%engine' => $engine, '%type' => $type, '%table' => $table, '%field' => $field)), 206 'warning'); 207 return $col['type']; 208 } 209 } 210 211 /** 212 * Convert an engine-specific data type into a Schema type. 213 */ 214 function schema_schema_type($type, $table, $field, $engine = NULL) { 215 $map = schema_engine_invoke($engine, 'schema_type_map'); 216 $type = strtolower($type); 217 if (isset($map[$type])) { 218 return explode(':', $map[$type]); 219 } else { 220 if (!variable_get('schema_suppress_type_warnings', FALSE)) { 221 drupal_set_message(t('Field @table.@field: no Schema type for @engine type @type.', array('@engine' => $engine, '@type' => $type, '@table' => $table, '@field' => $field)), 'warning'); 222 } 223 return array($type, 'normal'); 224 } 225 } 226 227 /** 228 * Compares two complete schemas. 229 * @param $ref is considered the reference copy 230 * @param $inspect is compared against it. If $inspect is NULL, a 231 * schema for the active database is generated and used. 232 */ 233 function schema_compare_schemas($ref, $inspect = NULL) { 234 if (! isset($inspect)) { 235 $inspect = schema_invoke('inspect'); 236 } 237 238 $info = array(); 239 240 // Error checks to consider adding: 241 // All type serial columns must be in an index or key. 242 // All columns in a primary or unique key must be NOT NULL. 243 244 // Error check: column type and default type must match 245 foreach ($ref as $t_name => $table) { 246 if (! isset($table['fields']) || !is_array($table['fields'])) { 247 drupal_set_message(t('Table %table: Missing or invalid \'fields\' array.', array('%table' => $t_name)), 'warning'); 248 continue; 249 } 250 251 foreach ($table['fields'] as $c_name => $col) { 252 switch ($col['type']) { 253 case 'int': 254 case 'float': 255 case 'numeric': 256 if (isset($col['default']) && 257 (! is_numeric($col['default']) || is_string($col['default']))) { 258 $info['warn'][] = t('%table.%column is type %type but its default %default is PHP type %phptype', array('%table' => $t_name, '%column' => $c_name, '%type' => $col['type'], '%default' => $col['default'], '%phptype' => gettype($col['default']))); 259 } 260 break; 261 262 default: 263 if (isset($col['default']) && !is_string($col['default'])) { 264 $info['warn'][] = t('%table.%column is type %type but its default %default is PHP type %phptype', array('%table' => $t_name, '%column' => $c_name, '%type' => $col['type'], '%default' => $col['default'], '%phptype' => gettype($col['default']))); 265 } 266 break; 267 } 268 } 269 } 270 271 // Error check: 'text' and 'blob' columns cannot have a default value 272 foreach ($ref as $t_name => $table) { 273 if (! isset($table['fields'])) { 274 continue; 275 } 276 277 foreach ($table['fields'] as $c_name => $col) { 278 switch ($col['type']) { 279 case 'text': 280 case 'blob': 281 if (isset($col['default'])) { 282 $info['warn'][] = t('%table.%column is type %type and may not have a default value', array('%table' => $t_name, '%column' => $c_name, '%type' => $col['type'])); 283 } 284 break; 285 } 286 } 287 } 288 289 // Error check: primary keys must be 'not null' 290 foreach ($ref as $t_name => $table) { 291 if (isset($table['primary key'])) { 292 $keys = db_field_names($table['primary key']); 293 foreach ($keys as $key) { 294 if (!isset($table['fields'][$key]['not null']) || $table['fields'][$key]['not null'] != TRUE) { 295 $info['warn'][] = t('%table.%column is part of the primary key but is not specified to be \'not null\'.', array('%table' => $t_name, '%column' => $key)); 296 } 297 } 298 } 299 } 300 301 foreach ($ref as $name => $table) { 302 if (isset($table['module'])) { 303 $module = $table['module']; 304 } 305 else { 306 $module = ''; 307 } 308 if (!isset($inspect[$name])) { 309 $info['missing'][$module][$name] = array('status' => 'missing'); 310 } else { 311 $status = schema_compare_table($table, $inspect[$name]); 312 $info[$status['status']][$module][$name] = $status; 313 unset($inspect[$name]); 314 } 315 } 316 317 foreach ($inspect as $name => $table) { 318 $info['extra'][] = $name; 319 } 320 return $info; 321 } 322 323 /** 324 * Compares a reference specification (such as one returned by a 325 * module's hook_schema) to an inspected specification from the 326 * database. 327 * @param $inspect if not provided, the database is inspected. 328 */ 329 function schema_compare_table($ref, $inspect = NULL) { 330 global $db_type; 331 $_db_type = $db_type; 332 if ($_db_type == 'mysqli') { 333 $_db_type = 'mysql'; 334 } 335 336 if (! isset($inspect)) { 337 $ref_name = db_prefix_tables('{'. $ref['name'] .'}'); 338 $inspect = schema_invoke('inspect', $ref_name); 339 $inspect = $inspect[$ref['name']]; 340 } 341 if (! isset($inspect)) { 342 return array('status' => 'missing'); 343 } 344 345 $reasons = $notes = array(); 346 $col_keys = array_flip( 347 array('type', 'size', 'not null', 'length', 'unsigned', 'default', 'scale', 'precision')); 348 foreach ($ref['fields'] as $colname => $col) { 349 350 // Many Schema types can map to the same engine type (e.g. in 351 // PostgresSQL, text:{small,medium,big} are all just text). When 352 // we inspect the database, we see the common type, but the 353 // reference we are comparing against can have a specific type. 354 // We therefore run the reference's specific type through the 355 // type conversion cycle to get its common type for comparison. 356 // 357 // Sadly, we need a special-case hack for 'serial'. 358 $serial = ($col['type'] == 'serial' ? TRUE : FALSE); 359 $name = isset($ref['name']) ? $ref['name'] : ''; 360 $dbtype = schema_engine_type($col, $name, $colname); 361 list($col['type'], $col['size']) = schema_schema_type($dbtype, $name, $colname); 362 if ($serial) { 363 $col['type'] = 'serial'; 364 } 365 366 // If an engine-specific type is specified, use it. XXX $inspect 367 // will contain the schema type for the engine type, if one 368 // exists, whereas dbtype_type contains the engine type. 369 if (isset($col[$_db_type .'_type'])) { 370 $col['type'] = $col[$_db_type .'_type']; 371 } 372 373 $col = array_intersect_key($col, $col_keys); 374 if (! isset($inspect['fields'][$colname])) { 375 $reasons[] = "$colname: not in database"; 376 continue; 377 } 378 379 // Account for schemas that contain unnecessary 'default' => NULL 380 if (!isset($col['default']) || 381 (is_null($col['default']) && !isset($inspect['fields'][$colname]['default']))) { 382 unset($col['default']); 383 } 384 385 $kdiffs = array(); 386 foreach ($col_keys as $key => $val) { 387 388 if ( !( 389 390 // First part tests that item exists for both and has same value in both places 391 ( isset($col[$key]) && !is_null($col[$key]) && $col[$key] !== FALSE 392 && isset($inspect['fields'][$colname][$key]) && $inspect['fields'][$colname][$key] !== FALSE 393 && $col[$key] == $inspect['fields'][$colname][$key] ) 394 395 // Second test is that it does not exist or exists but is null in both places 396 || ( ( !isset($col[$key]) || is_null($col[$key]) || $col[$key] === FALSE) 397 && ( !isset($inspect['fields'][$colname][$key]) || $inspect['fields'][$colname][$key] === FALSE) ) ) ) { 398 399 // One way or another, difference between the two so note it to explicitly identify it later. 400 $kdiffs[] = $key; 401 } 402 } 403 if (count($kdiffs) != 0) { 404 $reasons[] = "column $colname - difference". 405 ( count($kdiffs) > 1 ? 's' : '') ." on: ". 406 implode(', ', $kdiffs) ."<br/>declared: ". 407 schema_phpprint_column($col) .'<br/>actual: '. 408 schema_phpprint_column($inspect['fields'][$colname]); 409 } 410 unset($inspect['fields'][$colname]); 411 } 412 foreach ($inspect['fields'] as $colname => $col) { 413 $reasons[] = "$colname: unexpected column in database"; 414 } 415 416 if (isset($ref['primary key'])) { 417 if (! isset($inspect['primary key'])) { 418 $reasons[] = "primary key: missing in database"; 419 } 420 else if ($ref['primary key'] !== $inspect['primary key']) { 421 $reasons[] = ("primary key:<br />declared: ". 422 schema_phpprint_key($ref['primary key']).'<br />actual: '. 423 schema_phpprint_key($inspect['primary key'])); 424 } 425 } 426 else if (isset($inspect['primary key'])) { 427 $reasons[] = "primary key: missing in schema"; 428 } 429 430 foreach (array('unique keys', 'indexes') as $type) { 431 if (isset($ref[$type])) { 432 foreach ($ref[$type] as $keyname => $key) { 433 if (! isset($inspect[$type][$keyname])) { 434 $reasons[] = "$type $keyname: missing in database"; 435 continue; 436 } 437 // $key is column list 438 if ($key !== $inspect[$type][$keyname]) { 439 $reasons[] = ("$type $keyname:<br />declared: ". 440 schema_phpprint_key($key).'<br />actual: '. 441 schema_phpprint_key($inspect[$type][$keyname])); 442 } 443 unset($inspect[$type][$keyname]); 444 } 445 } 446 if (isset($inspect[$type])) { 447 foreach ($inspect[$type] as $keyname => $col) { 448 // this is not an error, the dba might have added it on purpose 449 $notes[] = "$type $keyname: unexpected (not an error)"; 450 } 451 } 452 } 453 454 $status = (count($reasons) ? 'different' : 'same'); 455 return array('status' => $status, 'reasons' => $reasons, 456 'notes' => $notes); 457 } 458 459 ////////////////////////////////////////////////////////////////////// 460 // Schema administration and UI 461 ////////////////////////////////////////////////////////////////////// 462 463 /** 464 * Implementation of hook_init(). 465 * Perform setup tasks. 466 */ 467 function schema_init() { 468 schema_require(); 469 } 470 471 function schema_require() { 472 static $done = 0; 473 if ($done++) { 474 return; 475 } 476 477 $path = drupal_get_path('module', 'schema'); 478 479 require_once("$path/schema_util.inc"); 480 481 // Load all our module 'on behalfs' so they will be available for 482 // any module (including this one) that needs them. 483 $files = drupal_system_listing('schema_.*\.inc$', $path.'/modules','name',0); 484 foreach($files as $file) { 485 // The filename format is very specific. It must be schema_MODULENAME.inc 486 $module = substr_replace($file->name, '', 0, 7); 487 require_once("./$file->filename"); 488 } 489 490 global $db_type, $schema_engines; 491 492 if (!isset($db_type)) { 493 return; 494 } 495 496 $schema_engines = array(); 497 if (0) { 498 // Load the schema database engine for the currently active database. 499 $engine = (drupal_get_path('module', 'schema'). 500 '/engines/schema_'.$db_type.'.inc'); 501 if (is_file($engine)) { 502 require_once($engine); 503 $schema_engines[] = $db_type; 504 } 505 } else { 506 // Load all Schema database engines. 507 $files = drupal_system_listing('schema_.*\.inc$',$path.'/engines','name',0); 508 foreach($files as $file) { 509 require_once("./$file->filename"); 510 $schema_engines[] = substr($file->filename, strlen($path)+16, -4); 511 } 512 } 513 514 if (array_search($db_type, $schema_engines) === FALSE) { 515 drupal_set_message('The Schema module does not support the "'.$db_type. 516 '" database type.', 'error'); 517 } 518 } 519 520 /** 521 * Implementation of hook_perm(). 522 */ 523 function schema_perm() { 524 return array('administer schema'); 525 } 526 527 /** 528 * Implementation of hook_menu(). 529 * Define menu items and page callbacks. 530 * admin/build/schema calls local task(default): schema_report() 531 * admin/build/schema/report calls local task: schema_report() 532 * admin/build/schema/describe calls local task: schema_describe() 533 * admin/build/schema/inspect calls local task: schema_inspect() 534 * admin/build/schema/sql calls local task: schema_sql() 535 * admin/build/schema/show calls local task: schema_show() 536 */ 537 function schema_menu() { 538 $items['admin/build/schema'] = array( 539 'title' => 'Schema', 540 'description' => 'Manage the database schema for this system.', 541 'page callback' => 'schema_report', 542 'access arguments' => array('administer schema'), 543 ); 544 545 $items['admin/build/schema/report'] = array( 546 'title' => 'Compare', 547 'type' => MENU_DEFAULT_LOCAL_TASK, 548 'page callback' => 'schema_report', 549 'weight' => -10, 550 'access arguments' => array('administer schema'), 551 ); 552 553 $items['admin/build/schema/describe'] = array( 554 'title' => 'Describe', 555 'type' => MENU_LOCAL_TASK, 556 'page callback' => 'schema_describe', 557 'weight' => -8, 558 'access arguments' => array('administer schema'), 559 ); 560 561 $items['admin/build/schema/inspect'] = array( 562 'title' => 'Inspect', 563 'type' => MENU_LOCAL_TASK, 564 'page callback' => 'schema_inspect', 565 'weight' => -6, 566 'access arguments' => array('administer schema'), 567 ); 568 569 $items['admin/build/schema/sql'] = array( 570 'title' => 'SQL', 571 'type' => MENU_LOCAL_TASK, 572 'page callback' => 'schema_sql', 573 'weight' => -4, 574 'access arguments' => array('administer schema'), 575 ); 576 577 // This can't work unless we rename the functions in database.*.inc. 578 global $db_type, $schema_engines; 579 if (FALSE && isset($schema_engines) && is_array($schema_engines)) { 580 foreach ($schema_engines as $engine) { 581 $items['admin/build/schema/sql/'.$engine] = array( 582 'title' => t($engine), 583 'type' => ($engine == $db_type ? MENU_DEFAULT_LOCAL_TASK : 584 MENU_LOCAL_TASK), 585 'page callback' => 'schema_sql', 586 'callback arguments' => $engine, 587 'access arguments' => array('administer schema'), 588 ); 589 } 590 } 591 592 $items['admin/build/schema/show'] = array( 593 'title' => 'Show', 594 'type' => MENU_LOCAL_TASK, 595 'page callback' => 'schema_show', 596 'weight' => -2, 597 'access arguments' => array('administer schema'), 598 ); 599 600 $items['admin/build/schema/settings'] = array( 601 'title' => 'Settings', 602 'type' => MENU_LOCAL_TASK, 603 'page callback' => 'drupal_get_form', 604 'page arguments' => array('schema_settings'), 605 'weight' => 0, 606 'access arguments' => array('administer schema'), 607 ); 608 609 return $items; 610 } 611 612 function _schema_process_description($desc) { 613 return preg_replace('@{([a-z_]+)}@i', '<a href="#" onclick="Drupal.toggleFieldset($(\'#table-$1\')[0]); return false;">$1</a>', $desc); 614 } 615 616 /** 617 * "Describe" menu callback. 618 */ 619 function schema_describe() { 620 $schema = drupal_get_schema(NULL, TRUE); 621 ksort($schema); 622 $row_hdrs = array(t('Name'), t('Type[:Size]'), t('Null?'), t('Default')); 623 624 $output = <<<EOT 625 <p>This page describes the Drupal database schema. Click on a table name 626 to see that table's description and fields. Table names within a table or 627 field description are hyperlinks to that table's description.</p> 628 EOT; 629 630 $default_table_description = t('TODO: please describe this table!'); 631 $default_field_description = t('TODO: please describe this field!'); 632 foreach ($schema as $t_name => $t_spec) { 633 $rows = array(); 634 foreach ($t_spec['fields'] as $c_name => $c_spec) { 635 $row = array(); 636 $row[] = $c_name; 637 $type = $c_spec['type']; 638 if (!empty($c_spec['length'])) { 639 $type .= '('. $c_spec['length'] .')'; 640 } 641 if (!empty($c_spec['scale']) && !empty($c_spec['precision'])) { 642 $type .= '('. $c_spec['precision'] .', '. $c_spec['scale'] .')'; 643 } 644 if (!empty($c_spec['size']) && $c_spec['size'] != 'normal') { 645 $type .= ':'.$c_spec['size']; 646 } 647 if ($c_spec['type'] == 'int' && !empty($c_spec['unsigned'])) { 648 $type .= ', unsigned'; 649 } 650 $row[] = $type; 651 $row[] = !empty($c_spec['not null']) ? 'NO' : 'YES'; 652 $row[] = isset($c_spec['default']) ? (is_string($c_spec['default']) ? '\''. $c_spec['default']. '\'' : $c_spec['default']) : ''; 653 $rows[] = $row; 654 if (!empty($c_spec['description']) && $c_spec['description'] != $default_field_description) { 655 $desc = _schema_process_description($c_spec['description']); 656 $rows[] = array(array('colspan' => count($row_hdrs), 'data' => $desc)); 657 } else { 658 drupal_set_message(_schema_process_description(t('Field {!table}.@field has no description.', array('!table' => $t_name, '@field' => $c_name))), 'warning'); 659 } 660 } 661 662 if (empty($t_spec['description']) || $t_spec['description'] == $default_table_description) { 663 drupal_set_message(_schema_process_description(t('Table {!table} has no description.', array('!table' => $t_name))), 'warning'); 664 } 665 666 $form = array(); 667 $form[$t_name] = array( 668 '#type' => 'fieldset', 669 '#title' => t('@table (@module module)', 670 array('@table' => $t_name, '@module' => isset($t_spec['module']) ? $t_spec['module'] : '')), 671 '#description' => !empty($t_spec['description']) ? _schema_process_description($t_spec['description']) : '', 672 '#collapsible' => TRUE, 673 '#collapsed' => TRUE, 674 '#attributes' => array('id' => 'table-'.$t_name)); 675 $form[$t_name]['content'] = array('#value' => theme('table', $row_hdrs, $rows)); 676 $output .= drupal_render($form); 677 } 678 679 return $output; 680 } 681 682 683 /** 684 * "Report" menu callback. 685 * This function just massages the data returned by 686 * schema_compare_schemas() into HTML. 687 */ 688 function schema_report() { 689 $states = array( 690 'same' => t('Match'), 691 'different' => t('Mismatch'), 692 'missing' => t('Missing'), 693 'extra' => t('Extra'), 694 ); 695 $descs = array( 696 'same' => 'Tables for which the schema and database agree.', 697 'different' => 'Tables for which the schema and database are different.', 698 'missing' => 'Tables in the schema that are not present in the database.', 699 'extra' => '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.', 700 ); 701 702 $schema = drupal_get_schema(NULL, TRUE); 703 $info = schema_compare_schemas($schema); 704 705 foreach ($info as $state => $modules) { 706 $counts[$state] = 0; 707 $data[$state] = ($state == 'extra' ? array() : ''); 708 709 if ($state == 'extra') { 710 $data[$state] = array_merge($data[$state], $modules); 711 $counts[$state] += count($modules); 712 continue; 713 } 714 else if ($state == 'warn') { 715 foreach ($modules as $msg) { 716 drupal_set_message($msg, 'warning'); 717 } 718 continue; 719 } 720 721 foreach ($modules as $module => $tables) { 722 $counts[$state] += count($tables); 723 switch ($state) { 724 case 'same': 725 case 'missing': 726 $data[$state] .= theme('item_list', array_keys($tables), $module); 727 break; 728 729 case 'different': 730 $items = array(); 731 foreach ($tables as $name => $stuff) { 732 $items[] = "<h4>$name</h4>".theme('item_list', 733 array_merge($tables[$name]['reasons'], $tables[$name]['notes'])); 734 } 735 736 $form = array(); 737 $form[$module] = array( 738 '#type' => 'fieldset', 739 '#title' => t($module), 740 '#collapsible' => TRUE, 741 '#collapsed' => TRUE, 742 '#value' => '', 743 ); 744 $form[$module]['content'] = array( 745 '#value' => theme('item_list', $items), 746 ); 747 $data[$state] .= drupal_render($form); 748 break; 749 } 750 } 751 } 752 if (isset($data['extra'])) { 753 $data['extra'] = theme('item_list', $data['extra']); 754 } 755 756 $form = array(); 757 $weight = 0; 758 foreach ($states as $state => $content) { 759 $content = (isset($data[$state]) ? $data[$state] : ''); 760 $form[$state] = array( 761 '#type' => 'fieldset', 762 '#title' => t('@state (@count)', 763 array('@state' => $states[$state], '@count' => isset($counts[$state]) ? $counts[$state] : 0)), 764 '#description' => t($descs[$state]), 765 '#collapsible' => TRUE, 766 '#collapsed' => TRUE, 767 '#weight' => $weight++, 768 '#value' => '', 769 ); 770 $form[$state]['content'] = array( 771 '#type' => 'markup', 772 '#value' => $content); 773 } 774 775 $output = <<<EOT 776 <p>This page compares the live database as it currently exists against 777 the combination of all schema information provided by all enabled modules.</p> 778 EOT; 779 780 $output .= drupal_render($form); 781 return $output; 782 } 783 784 785 /** 786 * "Inspect" menu callback. 787 */ 788 function schema_inspect() { 789 $mods = module_list(); 790 sort($mods); 791 $mods = array_flip($mods); 792 $schema = drupal_get_schema(NULL, TRUE); 793 $inspect = schema_invoke('inspect'); 794 foreach ($inspect as $name => $table) { 795 $module = isset($schema[$name]['module']) ? $schema[$name]['module'] : 'Unknown'; 796 if (!isset($form[$module])) { 797 $form[$module] = array( 798 '#type' => 'fieldset', 799 '#access' => TRUE, 800 '#title' => check_plain($module), 801 '#collapsible' => TRUE, 802 '#collapsed' => ($module != 'Unknown'), 803 '#weight' => ($module == 'Unknown' ? 0 : $mods[$module]+1), 804 '#value' => ''); 805 } 806 $form[$module][$name] = array( 807 '#type' => 'markup', 808 '#value' => '<textarea style="width:100%" rows="10">'.check_plain(schema_phpprint_table($name, $table)).'</textarea>'); 809 } 810 811 $output = <<<EOT 812 <p>This page shows the live database schema as it currently 813 exists on this system. Known tables are grouped by the module that 814 defines them; unknown tables are all grouped together.</p> 815 816 <p>To implement hook_schema() for a module that has existing tables, copy 817 the schema structure for those tables directly into the module's 818 hook_schema() and return \$schema.</p> 819 EOT; 820 821 $output .= drupal_render($form); 822 823 return $output; 824 } 825 826 827 /** 828 * "SQL" menu callback. 829 */ 830 function schema_sql($engine = NULL) { 831 $schema = drupal_get_schema(NULL, TRUE); 832 $sql = ''; 833 foreach ($schema as $name => $table) { 834 if (substr($name, 0, 1) == '#') { 835 continue; 836 } 837 if ($engine) { 838 $stmts = call_user_func('schema_'.$engine.'_create_table_sql', $table); 839 } else { 840 $stmts = db_create_table_sql($name, $table); 841 } 842 843 $sql .= implode(";\n", $stmts).";\n\n"; 844 } 845 846 $output = <<<EOT 847 <p>This page shows the CREATE TABLE statements that the Schema module 848 generates for the selected database engine for each table defined by a 849 module. It is for debugging purposes.</p> 850 <textarea style="width:100%" rows="30">$sql</textarea> 851 EOT; 852 853 return $output; 854 } 855 856 /** 857 * "Show" menu callback. 858 * Displays drupal schema as php code, so you can reuse it 859 * as you need. 860 */ 861 function schema_show() { 862 $schema = drupal_get_schema(NULL, TRUE); 863 $show = var_export($schema,1); 864 865 $output = <<<EOT 866 <p>This page displays the Drupal database schema data structure. It is for 867 debugging purposes.</p> 868 869 <textarea style="width:100%" rows="30">$show</textarea> 870 EOT; 871 872 return $output; 873 } 874 875 function schema_settings() { 876 global $db_url; 877 if(is_array($db_url) && count($db_url) > 1){ 878 $form['schema_database_connection'] = array( 879 '#type' => 'select', 880 '#title' => t('Database connection to use'), 881 '#default_value' => variable_get('schema_database_connection', 'default'), 882 '#options' => array_combine(array_keys($db_url), array_keys($db_url)), 883 '#description' => t('If you use a secondary database other than the default 884 Drupal database you can select it here and use schema\'s "compare" and 885 "inspect" functions on that other database.'), 886 ); 887 } 888 $form['schema_status_report'] = array( 889 '#type' => 'checkbox', 890 '#title' => t('Include schema comparison reports in site status report'), 891 '#default_value' => variable_get('schema_status_report', TRUE), 892 '#description' => t('When checked, schema comparison reports are run on 893 the Administer page, and included in the site status report.'), 894 ); 895 $form['schema_suppress_type_warnings'] = array( 896 '#type' => 'checkbox', 897 '#title' => t('Suppress schema warnings.'), 898 '#default_value' => variable_get('schema_suppress_type_warnings', FALSE), 899 '#description' => t('When checked, missing schema type warnings will be suppressed.'), 900 ); 901 return system_settings_form($form); 902 } 903
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |