You are here

public static function FieldChangeHelper::changeSchema in Helper 7

1 call to FieldChangeHelper::changeSchema()
FieldChangeHelper::changeType in lib/FieldChangeHelper.php
Change a field's type, even if it has data.

File

lib/FieldChangeHelper.php, line 109

Class

FieldChangeHelper

Code

public static function changeSchema(array &$field, array $column_renames = array()) {

  // Update the field schema
  $old_schema = array_intersect_key($field, array(
    'columns' => '',
    'indexes' => '',
    'foreign keys' => '',
  ));
  module_load_install($field['module']);
  $new_schema = (array) module_invoke($field['module'], 'field_schema', $field);
  $new_schema += array(
    'columns' => array(),
    'indexes' => array(),
    'foreign keys' => array(),
  );
  $field['data']['columns'] = $new_schema['columns'];
  $field['data']['indexes'] = $new_schema['indexes'];
  $field['data']['foreign keys'] = $new_schema['foreign keys'];
  $data_table = _field_sql_storage_tablename($field);
  $revision_table = _field_sql_storage_revision_tablename($field);

  // Validate that all the columns described in the existing schema actually exist.
  foreach (array_keys($old_schema['columns']) as $old_column) {
    $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column);
    if (!db_field_exists($data_table, $old_column_name)) {
      throw new Exception();
    }
    if (!db_field_exists($revision_table, $old_column_name)) {
      throw new Exception();
    }

    // Attempt to re-use any columns that have the same name.
    // This can be skipped by setting $column_renames['column-name'] = FALSE;
    if (!empty($new_schema['columns'][$old_column]) && !isset($column_renames[$old_column])) {
      $column_renames[$old_column] = $old_column;
    }
  }

  // Validate that any columns to be renamed actually exist.
  foreach ($column_renames as $old_column => $new_column) {
    if (!isset($old_schema['columns'][$old_column])) {
      throw new Exception("Cannot rename field {$field['field_name']} column {$old_column} because it does not exist in the old schema.");
    }
    if (!isset($new_schema['columns'][$new_column])) {
      throw new Exception("Cannot rename field {$field['field_name']} column {$old_column} to {$new_column} because it does not exist in the new schema.");
    }
  }

  // Remove all existing indexes.
  foreach ($old_schema['indexes'] as $index => $index_fields) {
    $index_name = _field_sql_storage_indexname($field['field_name'], $index);
    if (db_index_exists($data_table, $index_name)) {
      watchdog('helper', "Dropped index {$data_table}.{$index_name}");
      db_drop_index($data_table, $index_name);
    }
    if (db_index_exists($revision_table, $index_name)) {
      watchdog('helper', "Dropped index {$revision_table}.{$index_name}");
      db_drop_index($revision_table, $index_name);
    }
  }

  // Rename any columns.
  foreach ($column_renames as $old_column => $new_column) {
    $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column);
    if ($new_column === FALSE) {
      db_drop_field($data_table, $old_column_name);
      watchdog('helper', "Dropped column {$data_table}.{$old_column_name}");
      db_drop_field($revision_table, $old_column_name);
      watchdog('helper', "Dropped column {$revision_table}.{$old_column_name}");
      unset($old_schema['columns'][$old_column]);
    }
    else {
      $new_column_name = _field_sql_storage_columnname($field['field_name'], $new_column);
      db_change_field($data_table, $old_column_name, $new_column_name, $new_schema['columns'][$new_column]);
      watchdog('helper', "Changed column {$data_table}.{$old_column_name}<br/><pre>" . print_r($new_schema['columns'][$new_column], TRUE) . '</pre>');
      db_change_field($revision_table, $old_column_name, $new_column_name, $new_schema['columns'][$new_column]);
      watchdog('helper', "Changed column {$revision_table}.{$old_column_name}<br/><pre>" . print_r($new_schema['columns'][$new_column], TRUE) . '</pre>');

      // Remove these fields so they aren't removed or added in the code below.
      unset($new_schema['columns'][$new_column]);
      unset($old_schema['columns'][$old_column]);
    }
  }

  // Remove any old columns.
  $old_columns = array_diff_key($old_schema['columns'], $new_schema['columns']);
  foreach (array_keys($old_columns) as $old_column) {
    $old_column_name = _field_sql_storage_columnname($field['field_name'], $old_column);
    db_drop_field($data_table, $old_column_name);
    watchdog('helper', "Dropped column {$data_table}.{$old_column_name}");
    db_drop_field($revision_table, $old_column_name);
    watchdog('helper', "Dropped column {$revision_table}.{$old_column_name}");
  }

  // Add any new columns.
  $new_columns = array_diff_key($new_schema['columns'], $old_schema['columns']);
  foreach (array_keys($new_columns) as $new_column) {
    $new_column_name = _field_sql_storage_columnname($field['field_name'], $new_column);
    db_add_field($data_table, $new_column_name, $new_schema['columns'][$new_column]);
    watchdog('helper', "Added column {$data_table}.{$new_column_name}");
    db_add_field($revision_table, $new_column_name, $new_schema['columns'][$new_column]);
    watchdog('helper', "Added column {$revision_table}.{$new_column_name}");
  }

  // Re-add indexes.
  foreach ($new_schema['indexes'] as $index => $index_fields) {
    foreach ($index_fields as &$index_field) {
      if (is_array($index_field)) {
        $index_field[0] = _field_sql_storage_columnname($field['field_name'], $index_field[0]);
      }
      else {
        $index_field = _field_sql_storage_columnname($field['field_name'], $index_field);
      }
    }
    $index_name = _field_sql_storage_indexname($field['field_name'], $index);
    db_add_index($data_table, $index_name, $index_fields);
    watchdog('helper', "Added index {$data_table}.{$index_name}<br/><pre>" . print_r($index_fields, TRUE) . '</pre>');
    db_add_index($revision_table, $index_name, $index_fields);
    watchdog('helper', "Added index {$revision_table}.{$index_name}<br/><pre>" . print_r($index_fields, TRUE) . '</pre>');
  }
}