| 5 install.php | hook_update_N() |
| 6 install.php | hook_update_N(&$sandbox) |
| 7 system.api.php | hook_update_N(&$sandbox) |
| 8 system.api.php | hook_update_N(&$sandbox) |
Perform a single update.
For each patch which requires a database change add a new hook_update_N() which will be called by update.php. The database updates are numbered sequentially according to the version of Drupal you are compatible with.
Schema updates should adhere to the Schema API: http://drupal.org/node/150215
Database updates consist of 3 parts:
- 1 digit for Drupal core compatibility
- 1 digit for your module's major release version (e.g. is this the 5.x-1.* (1) or 5.x-2.* (2) series of your module?)
- 2 digits for sequential counting starting with 00
The 2nd digit should be 0 for initial porting of your module to a new Drupal core API.
Examples:
- mymodule_update_5200()
- This is the first update to get the database ready to run mymodule 5.x-2.*.
- mymodule_update_6000()
- This is the required update for mymodule to run with Drupal core API 6.x.
- mymodule_update_6100()
- This is the first update to get the database ready to run mymodule 6.x-1.*.
- mymodule_update_6200()
- This is the first update to get the database ready to run mymodule 6.x-2.*. Users can directly update from 5.x-2.* to 6.x-2.* and they get all 60XX and 62XX updates, but not 61XX updates, because those reside in the 6.x-1.x branch only.
A good rule of thumb is to remove updates older than two major releases of Drupal. See hook_update_last_removed() to notify Drupal about the removals. For further information about releases and release numbers see: Maintaining a drupal.org project with Git
Never renumber update functions.
Implementations of this hook should be placed in a mymodule.install file in the same directory as mymodule.module. Drupal core's updates are implemented using the system module as a name and stored in database/updates.inc.
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: http://drupal.org/node/180528
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. If no message is returned, no message will be presented to the user.
Throws
DrupalUpdateException, PDOException In case of error, update hooks should throw an instance of DrupalUpdateException with a meaningful message for the user. If a database query fails for whatever reason, it will throw a PDOException.
Related topics
File
- modules/
system/ system.api.php, line 3277 - Hooks provided by Drupal core and the System module.
Code
<?php
function hook_update_N(&$sandbox) {
// For non-multipass updates, the signature can simply be;
// function hook_update_N() {
// For most 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, simply return nothing.
return t('The update did what it was supposed to do.');
// In case of an error, simply throw an exception with an error message.
throw new DrupalUpdateException('Something went wrong; here is what you should do.');
}
?> Login or register to post comments
Comments
#finished
When implementing a multi-pass update and using the
$sandboxparameter provided by batch API, note that the$sandbox['#finished']is not preserved across function calls.Do not use API functions supplied by .module files
The code inside a
hook_update_N()implementation should not call any API functions that are provided by any.modulefile, including its own, unless:drupal_load().See also:
Schema API Link is Very Misleading for D7
The link in the quote above points to a document that, while helpful, is written for drupal 6.x and makes no mention of the fact that many of the database functions have changed in D7, much less a link to the actual D7 Schema API, which can be found here http://api.drupal.org/api/drupal/includes--database--database.inc/group/... .
Description text for an update
The text for the update list on "update.php?op=selection" is the comment block of the update hook.
Means that:
<?php/**
* My Update
*/
function hook_update_7001(&$sandbox) {
}
?>
Will give you "7001 - My Update" in the list of updates.
A simpler hook_update_n function example
Instead of having to dissect the above example... I wrote a simple update hook function that loads every user (4 at a time) and performs an action on them.
The action currently is just a comment, because I just wanted to share a base template for the hook update, I hope someone finds this useful.
<?php
/**
*
* A hook update that goes through every user and performs an action
*
*/
function hook_update_7000(&$sandbox){
if(!isset($sandbox['progress'])){
$sandbox['progress'] = 0;
$sandbox['last_uid'] = 0;
$sandbox['limit'] = 4;
$sandbox['max'] = db_query('SELECT COUNT(DISTINCT uid) FROM {users}')->fetchField() - 1;
}
$q = db_query('SELECT uid FROM users WHERE uid > '.$sandbox['last_uid'].' LIMIT '.$sandbox['limit'].'')->fetchCol();
$user_array = user_load_multiple($q,array());
foreach($user_array as $loaded_user){
//Perform actions on an individual user
$sandbox['progress']++;
}
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
$sandbox['last_uid'] = $loaded_user->uid;
}
?>