blog-banner

Best Way To Add New Columns to Custom Table

  • Drupal 7
  • Drupal Module
  • Drupal Planet
  • HOOK_UPDATE_N()
  • Schema

Drupal Install Schema

 

Often times it is needed to create module-specific custom tables to store persistent data. Drupal offers a set of hooks in connection to this. Most commonly used among these are hook_schema() and hook_update_N(). The first hook, hook_schema() holds the structure of the table in the form of a PHP array. And since Drupal 7 drupal_install_schema()/drupal_uninstall_schema() are no longer needed to be called explicitly in hook_install()/hook_uninstall(). When the module is enabled for the first time, the structure of the table defined in hook_schema is parsed and the needed table(s) are created for the intended use.

However, the real-time use case at times requires adding the column to a table (or altering the table) after the module has been enabled. In such cases hook_update_N() comes into play.

Let's take the below code for instance,

function my_module_update_7001(&$sandbox) {
  $spec = array(
    'type' => 'int',
    'unsigned' => TRUE,
    'not null' => TRUE,  
  );
  db_add_field('my_table', 'my_column', $spec);
}
This code simply adds an integer column named `my_column` to table `my_table`. On running update.php (https://example.com/update.php). The database layer API does the needful to alter the table as needed (column adding in this case).
 
It is to be noted that the same column definition needs to be added to hook_schema() as well. Since there are chances that the module will be installed freshly again on another site.
 
The best way to go about this case is to define the schema array in hook_schema() mainly and reuse the same in hook_update_N().
/**
 * Implements hook_schema().
 */
function my_module_schema() {
  $schema = array();
  $schema['my_module_node_properties'] = array(
    'fields' => array(
      'nid' => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'vid' => array(
        'type' => 'int',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'my_column' => array(
        'type' => 'int',
        'size' => 'tiny',
        'unsigned' => TRUE,
        'not null' => TRUE,
      ),
      'new_column1' => array(
        'type' => 'int',
        'size' => 'tiny',
      ),
      'new_column2' => array(
        'type' => 'int',
      ),
    ),
    'primary key' => array('vid'),
    'indexes' => array('table_id' => array('vid', 'nid')),
  );
  return $schema;
}

/**
 * Add column1 and column2 fields to table {my_module_node_properties}
 */
function my_module_update_7004() {
  $table = 'my_module_node_properties';
  $schema = drupal_get_schema_unprocessed('my_module', $table);  
  foreach (array('new_column1', 'new_column2') as $field) {
    db_add_field($table, $field, $schema['fields'][$field]);
  }
}
The code above can be considered as best relevant for the subject we have been talking about. The table {my_module_node_properties} initially had nid, vid and my_column as fields. Later it was needed to add new_column1 and new_column2. Definition of the same have been added to hook_schema and in hook_update() using drupal_get_schema_unprocessed() API we get the field spec from unified source and eventually we pass it to db_add_field(). Of course, we could use module_invoke() API as well to get schema but drupal_get_schema_unprocessed() is a wrapper function besides calling module_invoke() to get schema, it does schema value checks as well.

 

Get awesome tech content in your inbox