Supposons la situation suivante:
Je développe un plugin. Le plugin nécessite une table de base de données personnalisée pour stocker certaines informations.
De mois en mois, je publie de nouvelles versions de mon plugin. Différentes versions pourraient avoir leurs propres ensembles de modifications de la structure et des données de la table. Par exemple:
Le problème:
Permet de considérer deux cas d'utilisation:
Ok, pour résoudre ces problèmes, implémentons le processus de mise à niveau en cascade qui gérera les deux cas d'utilisation.
Tout d’abord, implémentons notre hook d’activation de plugin, qui sera notre point d’entrée:
// define current plugin version
define( 'WPSE8170_PLUGIN_VERSION', '2.0.0' );
// define our database table name
define( 'WPSE8170_DB_TABLE', $GLOBALS['wpdb']->prefix . 'wpse8170_test_table' );
add_action( 'init', 'wpse8170_plugin_upgrade' ); // check database on init action, to be confident that our plugin database is up-to-date
register_activation_hook ( __FILE__, 'wpse8170_plugin_upgrade' );
function wpse8170_plugin_upgrade() {
$filter = 'wpse8170_upgrade_db';
$option = 'wpse8170_db_version';
// get current database version
$db_version = get_option( $option );
// if database version is not exists, lets create new and set it to '0.0.0'
if ( $db_version === false ) {
$db_version = '0.0.0';
add_option( $option, $db_version, '', 'yes' );
}
// check database version, if it equals to current plugin version, then no upgrades are required
if ( version_compare( $db_version, WPSE8170_PLUGIN_VERSION, '=' ) ) {
return;
}
// define our upgrade hooks, which will be called to upgrade database to a certain version
add_filter( $filter, 'wpse8170_upgrade_to_10000' ); // upgrade db to version 1.0
add_filter( $filter, 'wpse8170_upgrade_to_11000' ); // upgrade db to version 1.1
add_filter( $filter, 'wpse8170_upgrade_to_20000' ); // upgrade db to version 2.0
// apply our upgrade filter and update database version
update_option( $option, apply_filters( $filter, $db_version ) );
}
Avant de commencer à regarder les crochets de mise à niveau, créons une fonction d'assistance qui nous aidera à exécuter un ensemble de requêtes SQL:
function wpse8179_execute_upgrade_queries( array $queries ) {
global $wpdb;
foreach ( $queries as $query ) {
$wpdb->query( $query );
}
}
Enfin, voyons nos crochets de mise à niveau. Mettre à niveau la base de données de 0.0.0 à 1.0.0:
function wpse8170_upgrade_to_10000( $current_version ) {
// define version of current upgrade hook
$this_version = '1.0.0';
// if the version of current upgrade hook is less or equals to current database version, return it without any changes
if ( version_compare( $current_version, $this_version, '>=' ) ) {
return $current_version;
}
// execute all required queries to make database corresponding to current upgrade version
wpse8179_execute_upgrade_queries( array(
sprintf( "CREATE TABLE IF NOT EXISTS `%s` (`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `type` VARCHAR(15) NOT NULL, `data` TEXT NOT NULL, PRIMARY KEY (`id`) ) ENGINE = MyISAM", WPSE8170_DB_TABLE ),
// above queries could be merged into one, but added as an example
sprintf( "ALTER TABLE `%s` CHARACTER SET = utf8, COLLATE = utf8_general_ci;", WPSE8170_DB_TABLE ),
sprintf( "ALTER TABLE `%s` CHANGE COLUMN `data` `data` TEXT CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL;", WPSE8170_DB_TABLE ),
sprintf( "ALTER TABLE `%s` ADD INDEX `gchart_idx_type` (`type` ASC)", WPSE8170_DB_TABLE ),
) );
// return current upgrade version, which is equals to 1.0.0
return $this_version;
}
Mettre à niveau la base de données de 1.0.0 à 1.1.0:
function wpse8170_upgrade_to_11000( $current_version ) {
// define version of current upgrade hook
$this_version = '1.1.0';
// if the version of current upgrade hook is less or equals to current database version, return it without any changes
if ( version_compare( $current_version, $this_version, '>=' ) ) {
return $current_version;
}
// execute all required queries to make database corresponding to current upgrade version
wpse8179_execute_upgrade_queries( array(
// update table column type
sprintf( "ALTER TABLE `%s` CHANGE COLUMN `data` `data` MEDIUMTEXT NOT NULL", WPSE8170_DB_TABLE ),
// update table data
sprintf( "UPDATE `%s` SET ... WHERE ...", WPSE8170_DB_TABLE ),
) );
// return current upgrade version, which is equals to 1.1.0
return $this_version;
}
Mettre à niveau la base de données de 1.1.0 à 2.0.0:
function wpse8170_upgrade_to_20000( $current_version ) {
// define version of current upgrade hook
$this_version = '2.0.0';
// if the version of current upgrade hook is less or equals to current database version, return it without any changes
if ( version_compare( $current_version, $this_version, '>=' ) ) {
return $current_version;
}
// execute all required queries to make database corresponding to current upgrade version
wpse8179_execute_upgrade_queries( array(
// update table by adding two new columns
sprintf( "ALTER TABLE `%s` ...", WPSE8170_DB_TABLE ),
// update table data by splitting data from old column into two new
sprintf( "UPDATE `%s` SET ... WHERE ...", WPSE8170_DB_TABLE ),
// delete deprecated column from the table
sprintf( "ALTER TABLE `%s` ...", WPSE8170_DB_TABLE ),
) );
// return current upgrade version, which is equals to 2.0.0
return $this_version;
}
Voyons comment notre approche gère les deux cas d'utilisation:
wpse8170_upgrade_to_10000
car nous avons déjà la version de la base de données égale à 1.0.0
et passer par les hooks wpse8170_upgrade_to_11000
et wpse8170_upgrade_to_20000
pour mettre à niveau notre base de données vers la dernière version, y compris la version manquante 1.1.0.