1 system.api.php hook_update_N(&$sandbox)

Perform a single update.

For each change that requires one or more actions to be performed when updating a site, add a new hook_update_N(), which will be called by update.php. The documentation block preceding the update function is used as the description for the update on the pending updates at update.php. Schema updates should adhere to the Schema API.

Implementations of this hook should be placed in a my_module.install file in the same directory as my_module.module. Backdrop core's updates are implemented using the system module as a name and stored in database/updates.inc.

Implementations of hook_update_N() are named (module name)_update_(number). The numbers are composed of three parts:

  • 1 digit for Backdrop core compatibility.
  • 1 digit for your module's major release version (e.g., is this the 1.x-1.* (1) or 1.x-2.* (2) series of your module?). This digit should be 0 for initial porting of your module to a new Backdrop core API.
  • 2 digits for sequential counting, starting with 00.

Backdrop includes special considerations for updating from Drupal 7 websites. While Drupal 7 updates should be numbered 7xxx, Backdrop 1.x updates are numbered 1xxx. For the sake of compatibility, Backdrop will run any remaining 7xxx updates before running 1xxx updates. For the safest upgrade path possible, it's recommended Drupal 7 modules are running their latest version before attempting to upgrade to Backdrop equivalents. This upgrade compatibility also means that adhering to the naming convention of 1xxx for Backdrop updates is extremely important. Backdrop updates numbered greater than 6999 will have unexpected behavior, as they are reserved for Drupal 7 compatibility.

Examples:

  • my_module_update_1000(): This is the required update for my_module to run with Backdrop core API 1.x when upgrading from Drupal core API 7.x.
  • my_module_update_1100(): This is the first update to get the database/config ready to run my_module 1.x-1.*.
  • my_module_update_1200(): This is the first update to get the database/config ready to run my_module 1.x-2.*. Users can directly update from Drupal 7.x to Backdrop 1.x-2.*, and they get all the 10xx and 12xx updates, but not the 11xx updates, because those reside in the 1.x-1.x branch only.

A good rule of thumb is to remove updates older than two major releases of Backdrop. See hook_update_last_removed() to notify Backdrop about the removals. For further information about releases and release numbers see the Backdrop CMS Release Cycle handbook page

Because Backdrop keeps track of the last ran update based on the function name, you should never renumber update functions. It may result in updates being either skipped or run twice.

Module functions not in the install file cannot be counted on to be available from within a hook_update_N() function. In order to call a function from your my_module.module or an include file, you need to explicitly load that file first.

This is because if a module was previously enabled but is now disabled (and has not been uninstalled), update hooks will still be called for that module during system updates, but the my_module.module file (and any other files loaded by that one, including, for example, autoload information) will not have been loaded.

During site updates the schema of any module could be out of date. For this reason, caution is needed when using any API function within an update function - particularly CRUD functions, functions that depend on the schema (for example by using backdrop_write_record()), and any functions that invoke hooks. See Update versions of API functions for details.

If your update task is potentially time-consuming, you'll need to implement a multipass update to avoid PHP timeouts. Multipass updates use the $sandbox parameter provided by the batch API (normally, $context['sandbox']) to store information between successive calls, and the $sandbox['#finished'] value to provide feedback regarding completion level.

See the batch operations page for more information on how to use the Batch API.

Parameters

$sandbox: Stores information for multipass updates. See above for more information.

Return value

Optionally, update hooks may return a translated string that will be: displayed to the user after the update has completed. If no message is returned, no message will be presented to the user.

Throws

BackdropUpdateException, PDOException In case of error, update hooks should throw an instance of BackdropUpdateException with a meaningful message for the user. If a database query fails for whatever reason, it will throw a PDOException.

See also

Batch operations

Schema API

Update versions of API functions

hook_update_last_removed()

update_get_update_list()

Related topics

File

core/modules/system/system.api.php, line 3023
Hooks provided by Backdrop core and the System module.

Code

function hook_update_N(&$sandbox) {
  // For non-multipass updates the signature can be:
  // `function hook_update_N() {`.

  // Convert Drupal 7 variables to Backdrop config. Make sure these new config
  // settings and their default values exist in config/my_module.settings.json.
  $config = config('my_module.settings');
  $config->set('one', update_variable_get('my_module_one', '1.11'));
  $config->set('two', update_variable_get('my_module_two', '2.22'));
  $config->save();
  update_variable_del('my_module_one');
  update_variable_del('my_module_two');

  // Update existing config with a new setting. Make sure the new setting and
  // its default value exists in `config/my_module.settings.json`.
  config_set('my_module.settings', 'three', '3.33');

  // For most site updates, the following is sufficient.
  db_add_field('mytable1', 'newcol', array('type' => 'int', 'not null' => TRUE, 'description' => 'My new integer column.'));

  // However, for more complex operations that may take a long time, you may
  // hook into Batch API as in the following example.
  // Update 3 users at a time to have an exclamation point after their names.
  // (They're really happy that we can do batch API in this hook!)
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['current_uid'] = 0;
    // We'll -1 to disregard the uid 0...
    $sandbox['max'] = db_query('SELECT COUNT(DISTINCT uid) FROM {users}')->fetchField() - 1;
  }

  $users = db_select('users', 'u')
    ->fields('u', array('uid', 'name'))
    ->condition('uid', $sandbox['current_uid'], '>')
    ->range(0, 3)
    ->orderBy('uid', 'ASC')
    ->execute();

  foreach ($users as $user) {
    $user->name .= '!';
    db_update('users')
      ->fields(array('name' => $user->name))
      ->condition('uid', $user->uid)
      ->execute();

    $sandbox['progress']++;
    $sandbox['current_uid'] = $user->uid;
  }

  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);

  // To display a message to the user when the update is completed, return it.
  // If you do not want to display a completion message, return nothing.
  return t('The update did what it was supposed to do.');

  // In case of an error, throw an exception with an error message.
  throw new BackdropUpdateException('Something went wrong; here is what you should do.');
}