aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/includes')
-rw-r--r--phpBB/includes/constants.php1
-rw-r--r--phpBB/includes/db/migration.php79
-rw-r--r--phpBB/includes/db/migrator.php227
3 files changed, 307 insertions, 0 deletions
diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index 68af41ab20..68c96a2759 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -237,6 +237,7 @@ define('ICONS_TABLE', $table_prefix . 'icons');
define('LANG_TABLE', $table_prefix . 'lang');
define('LOG_TABLE', $table_prefix . 'log');
define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts');
+define('MIGRATIONS_TABLE', $table_prefix . 'migrations');
define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache');
define('MODULES_TABLE', $table_prefix . 'modules');
define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options');
diff --git a/phpBB/includes/db/migration.php b/phpBB/includes/db/migration.php
new file mode 100644
index 0000000000..f96fcb9568
--- /dev/null
+++ b/phpBB/includes/db/migration.php
@@ -0,0 +1,79 @@
+<?php
+/**
+*
+* @package db
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Abstract base class for database migrations
+*
+* Each migration consists of a set of schema and data changes to be implemented
+* in a subclass. This class provides various utility methods to simplify editing
+* a phpBB.
+*
+* @package db
+*/
+class phpbb_db_migration
+{
+ var $db;
+ var $db_tools;
+
+ /**
+ * Migration constructor
+ *
+ * @param dbal $db Connected database abstraction instance
+ * @param phpbb_db_tools $db_tools Instance of db schema manipulation tools
+ */
+ function phpbb_db_migration(&$db, &$db_tools)
+ {
+ $this->db = &$db;
+ $this->db_tools = &$db_tools;
+ }
+
+ /**
+ * Defines other migrationsto be applied first (abstract method)
+ *
+ * @return array An array of migration class names
+ */
+ function depends_on()
+ {
+ return array();
+ }
+
+ /**
+ * Updates the database schema
+ *
+ * @return null
+ */
+ function update_schema()
+ {
+ }
+
+ /**
+ * Updates data
+ *
+ * @return null
+ */
+ function update_data()
+ {
+ }
+
+ /**
+ * Adds a column to a database table
+ */
+ function db_column_add($table_name, $column_name, $column_data)
+ {
+ $this->db_tools->sql_column_add($table_name, $column_name, $column_data);
+ }
+}
diff --git a/phpBB/includes/db/migrator.php b/phpBB/includes/db/migrator.php
new file mode 100644
index 0000000000..d5d938ca28
--- /dev/null
+++ b/phpBB/includes/db/migrator.php
@@ -0,0 +1,227 @@
+<?php
+/**
+*
+* @package db
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* The migrator is responsible for applying new migrations in the correct order.
+*
+* @package db
+*/
+class phpbb_db_migrator
+{
+ var $db;
+ var $db_tools;
+
+ var $migrations_table;
+ var $migration_state;
+
+ var $migrations;
+
+ /**
+ * Constructor of the database migrator
+ *
+ * @param dbal $db Connected database abstraction instance
+ * @param phpbb_db_tools $db_tools Instance of db schema manipulation tools
+ * @param string $migrations_table The name of the db table storing
+ * information on applied migrations
+ */
+ function phpbb_db_migrator(&$db, &$db_tools, $migrations_table)
+ {
+ $this->db = &$db;
+ $this->db_tools = &$db_tools;
+ $this->migrations_table = $migrations_table;
+ $this->migrations = array();
+
+ $this->load_migration_state();
+ }
+
+ /**
+ * Loads all migrations and their application state from the database.
+ *
+ * @return null
+ */
+ function load_migration_state()
+ {
+ $sql = "SELECT *
+ FROM " . $this->migrations_table;
+ $result = $this->db->sql_query($sql);
+
+ $this->migration_state = array();
+ while ($migration = $this->db->sql_fetchrow($result))
+ {
+ $this->migration_state[$migration['migration_name']] = $migration;
+ }
+
+ $this->db->sql_freeresult($result);
+ }
+
+ /**
+ * Sets the list of available migration class names to the given array.
+ *
+ * @param array $class_names An array of migration class names
+ * @return null
+ */
+ function set_migrations($class_names)
+ {
+ $this->migrations = $class_names;
+ }
+
+ /**
+ * Runs a single update step from the next migration to be applied.
+ *
+ * The update step can either be a schema or a (partial) data update. To
+ * check if update() needs to be called again use the finished() method.
+ *
+ * @return null
+ */
+ function update()
+ {
+ foreach ($this->migrations as $name)
+ {
+ if (!isset($this->migration_state[$name]) ||
+ !$this->migration_state[$name]['migration_schema_done'] ||
+ !$this->migration_state[$name]['migration_data_done'])
+ {
+ if (!$this->try_apply($name))
+ {
+ continue;
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Attempts to apply a step of the given migration or one of its dependencies
+ *
+ * @param string The class name of the migration
+ * @return bool Whether any update step was successfully run
+ */
+ function try_apply($name)
+ {
+ if (!class_exists($name))
+ {
+ return false;
+ }
+
+ $migration =& new $name($this->db, $this->db_tools);
+ $state = (isset($this->migration_state[$name])) ?
+ $this->migration_state[$name] :
+ array(
+ 'migration_schema_done' => false,
+ 'migration_data_done' => false,
+ 'migration_data_state' => '',
+ );
+
+ $depends = $migration->depends_on();
+
+ foreach ($depends as $depend)
+ {
+ if (!isset($this->migration_state[$depend]) ||
+ !$this->migration_state[$depend]['migration_schema_done'] ||
+ !$this->migration_state[$depend]['migration_data_done'])
+ {
+ return $this->try_apply($depend);
+ }
+ }
+
+ if (!$state['migration_schema_done'])
+ {
+ $migration->update_schema();
+ $state['migration_schema_done'] = true;
+ }
+ else
+ {
+ $migration->update_data();
+ $state['migration_data_done'] = true;
+ }
+
+ $sql = 'UPDATE ' . $this->migrations_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $state) . "
+ WHERE migration_name = '" . $this->db->sql_escape($name) . "'";
+ $this->db->sql_query($sql);
+
+ $this->migration_state[$name] = $state;
+
+ return true;
+ }
+
+ /**
+ * Checks if a migration's dependencies can even theoretically be satisfied.
+ *
+ * @param string $name The class name of the migration
+ * @return bool Whether the migration cannot be fulfilled
+ */
+ function unfulfillable($name)
+ {
+ if (isset($this->migration_state[$name]))
+ {
+ return false;
+ }
+
+ if (!class_exists($name))
+ {
+ return true;
+ }
+
+ $migration =& new $name($this->db, $this->db_tools);
+ $depends = $migration->depends_on();
+
+ foreach ($depends as $depend)
+ {
+ if ($this->unfulfillable($depend))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether all available, fulfillable migrations have been applied.
+ *
+ * @return bool Whether the migrations have been applied
+ */
+ function finished()
+ {
+ foreach ($this->migrations as $name)
+ {
+ if (!isset($this->migration_state[$name]))
+ {
+ // skip unfulfillable migrations, but fulfillables mean we
+ // are not finished yet
+ if ($this->unfulfillable($name))
+ {
+ continue;
+ }
+ return false;
+ }
+
+ $migration = $this->migration_state[$name];
+
+ if (!$migration['migration_schema_done'] || !$migration['migration_data_done'])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}