[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/schema/ -> schema.module (source)

   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  


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7