2011-01-31 19:38:04 +02:00
|
|
|
<?php defined('SYSPATH') or die('No direct script access.');
|
2010-12-24 19:52:58 +02:00
|
|
|
|
|
|
|
/**
|
2011-07-02 09:18:05 +03:00
|
|
|
* The migration manager is responsible for locating migration files, syncing
|
|
|
|
* them with the migrations table in the database and selecting any migrations
|
2010-12-24 19:52:58 +02:00
|
|
|
* that need to be executed in order to reach a target version
|
|
|
|
*
|
|
|
|
* @author Matt Button <matthew@sigswitch.com>
|
2011-01-31 19:27:21 +02:00
|
|
|
*/
|
2010-12-24 19:52:58 +02:00
|
|
|
class Minion_Migration_Manager {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The database connection that sould be used
|
|
|
|
* @var Kohana_Database
|
|
|
|
*/
|
|
|
|
protected $_db;
|
|
|
|
|
2010-12-28 19:51:17 +02:00
|
|
|
/**
|
|
|
|
* Model used to interact with the migrations table in the database
|
|
|
|
* @var Model_Minion_Migration
|
|
|
|
*/
|
|
|
|
protected $_model;
|
|
|
|
|
2010-12-30 05:22:32 +02:00
|
|
|
/**
|
|
|
|
* Whether this is a dry run migration
|
|
|
|
* @var boolean
|
|
|
|
*/
|
|
|
|
protected $_dry_run = FALSE;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A set of SQL queries that were generated on the dry run
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $_dry_run_sql = array();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set of migrations that were executed
|
|
|
|
*/
|
|
|
|
protected $_executed_migrations = array();
|
|
|
|
|
|
|
|
|
2010-12-24 19:52:58 +02:00
|
|
|
/**
|
|
|
|
* Constructs the object, allows injection of a Database connection
|
|
|
|
*
|
2010-12-28 19:51:17 +02:00
|
|
|
* @param Kohana_Database The database connection that should be passed to migrations
|
|
|
|
* @param Model_Minion_Migration Inject an instance of the minion model into the manager
|
2010-12-24 19:52:58 +02:00
|
|
|
*/
|
2010-12-28 19:51:17 +02:00
|
|
|
public function __construct(Kohana_Database $db, Model_Minion_Migration $model = NULL)
|
2010-12-24 19:52:58 +02:00
|
|
|
{
|
2011-01-31 19:27:21 +02:00
|
|
|
if ($model === NULL)
|
2010-12-28 19:51:17 +02:00
|
|
|
{
|
|
|
|
$model = new Model_Minion_Migration($db);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->_db = $db;
|
|
|
|
$this->_model = $model;
|
2010-12-24 19:52:58 +02:00
|
|
|
}
|
|
|
|
|
2010-12-29 06:26:43 +02:00
|
|
|
/**
|
|
|
|
* Set the database connection to be used
|
2011-07-02 09:18:05 +03:00
|
|
|
*
|
2010-12-29 06:26:43 +02:00
|
|
|
* @param Kohana_Database Database connection
|
|
|
|
* @return Minion_Migration_Manager
|
|
|
|
*/
|
|
|
|
public function set_db(Kohana_Database $db)
|
|
|
|
{
|
|
|
|
$this->_db = $db;
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the model to be used in the rest of the app
|
|
|
|
*
|
|
|
|
* @param Model_Minion_Migration Model instance
|
|
|
|
* @return Minion_Migration_Manager
|
|
|
|
*/
|
|
|
|
public function set_model(Model_Minion_Migration $model)
|
|
|
|
{
|
|
|
|
$this->_model = $model;
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2010-12-30 05:22:32 +02:00
|
|
|
/**
|
|
|
|
* Set whether the manager should execute a dry run instead of a real run
|
|
|
|
*
|
|
|
|
* @param boolean Whether we should do a dry run
|
|
|
|
* @return Minion_Migration_Manager
|
|
|
|
*/
|
|
|
|
public function set_dry_run($dry_run)
|
|
|
|
{
|
|
|
|
$this->_dry_run = (bool) $dry_run;
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-07-02 09:18:05 +03:00
|
|
|
* Returns a set of queries that would've been executed had dry run not been
|
2010-12-30 05:22:32 +02:00
|
|
|
* enabled. If dry run was not enabled, this returns an empty array
|
|
|
|
*
|
|
|
|
* @return array SQL Queries
|
|
|
|
*/
|
|
|
|
public function get_dry_run_sql()
|
|
|
|
{
|
|
|
|
return $this->_dry_run_sql;
|
|
|
|
}
|
|
|
|
|
2010-12-31 02:51:07 +02:00
|
|
|
/**
|
|
|
|
* Returns a set of executed migrations
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function get_executed_migrations()
|
|
|
|
{
|
|
|
|
return $this->_executed_migrations;
|
|
|
|
}
|
|
|
|
|
2010-12-28 07:02:27 +02:00
|
|
|
/**
|
2011-02-17 22:43:04 +02:00
|
|
|
* Run migrations in the specified groups so as to reach specified targets
|
2010-12-28 07:02:27 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
2011-02-17 22:43:04 +02:00
|
|
|
* @param array Set of groups to update, empty array means all
|
|
|
|
* @param array Versions for specified groups
|
2010-12-29 06:30:25 +02:00
|
|
|
* @return array Array of all migrations that were successfully applied
|
2010-12-28 07:02:27 +02:00
|
|
|
*/
|
2011-02-18 04:07:41 +02:00
|
|
|
public function run_migration($group = array(), $target = TRUE)
|
2010-12-28 07:02:27 +02:00
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
list($migrations, $is_up) = $this->_model->fetch_required_migrations($group, $target);
|
|
|
|
|
|
|
|
$method = $is_up ? 'up' : 'down';
|
2010-12-29 01:23:36 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
foreach ($migrations as $migration)
|
2010-12-29 01:23:36 +02:00
|
|
|
{
|
2011-06-27 22:57:21 +03:00
|
|
|
if ($method == 'down' AND $migration['timestamp'] <= Kohana::$config->load('minion/migration')->lowest_migration)
|
2011-05-12 22:14:09 +03:00
|
|
|
{
|
|
|
|
Minion_CLI::write(
|
2011-06-27 22:57:21 +03:00
|
|
|
'You\'ve reached the lowest migration allowed by your config: '.Kohana::$config->load('minion/migration')->lowest_migration,
|
2011-05-12 22:14:09 +03:00
|
|
|
'red'
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-02 09:18:05 +03:00
|
|
|
$filename = $this->_model->get_filename_from_migration($migration);
|
2010-12-29 01:23:36 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
if ( ! ($file = Kohana::find_file('migrations', $filename, FALSE)))
|
2010-12-29 01:23:36 +02:00
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
throw new Kohana_Exception(
|
2011-07-02 09:18:05 +03:00
|
|
|
'Cannot load migration :migration (:file)',
|
2011-02-18 04:07:41 +02:00
|
|
|
array(
|
2011-07-02 09:18:05 +03:00
|
|
|
':migration' => $migration['id'],
|
2011-02-18 04:07:41 +02:00
|
|
|
':file' => $filename
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2010-12-29 01:23:36 +02:00
|
|
|
|
2011-07-02 09:18:05 +03:00
|
|
|
$class = $this->_model->get_class_from_migration($migration);
|
2010-12-29 01:23:36 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
include_once $file;
|
2010-12-29 01:23:36 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
$instance = new $class($migration);
|
2011-01-21 02:45:35 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
$db = $this->_get_db_instance($instance->get_database_connection());
|
2010-12-29 06:30:25 +02:00
|
|
|
|
2011-07-02 09:18:05 +03:00
|
|
|
try
|
2011-02-18 04:07:41 +02:00
|
|
|
{
|
|
|
|
$instance->$method($db);
|
|
|
|
}
|
|
|
|
catch(Database_Exception $e)
|
|
|
|
{
|
|
|
|
throw new Minion_Migration_Exception($e->getMessage(), $migration);
|
|
|
|
}
|
2010-12-31 02:51:07 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
if ($this->_dry_run)
|
|
|
|
{
|
2011-05-12 22:23:15 +03:00
|
|
|
$this->_dry_run_sql[$migration['group']][$migration['timestamp']] = $db->reset_query_stack();
|
2011-02-18 04:07:41 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$this->_model->mark_migration($migration, $is_up);
|
2010-12-29 01:23:36 +02:00
|
|
|
}
|
2011-02-18 04:07:41 +02:00
|
|
|
|
|
|
|
$this->_executed_migrations[] = $migration;
|
2010-12-29 01:23:36 +02:00
|
|
|
}
|
2010-12-28 07:02:27 +02:00
|
|
|
}
|
|
|
|
|
2010-12-24 19:52:58 +02:00
|
|
|
/**
|
|
|
|
* Syncs all available migration files with the database
|
|
|
|
*
|
|
|
|
* @chainable
|
|
|
|
* @return Minion_Migration_Manager Chainable instance
|
|
|
|
*/
|
2010-12-28 07:02:27 +02:00
|
|
|
public function sync_migration_files()
|
2010-12-24 19:52:58 +02:00
|
|
|
{
|
2010-12-29 02:46:07 +02:00
|
|
|
// Get array of installed migrations with the id as key
|
|
|
|
$installed = $this->_model->fetch_all('id');
|
2010-12-24 19:52:58 +02:00
|
|
|
|
2011-01-21 01:53:59 +02:00
|
|
|
$available = $this->_model->available_migrations();
|
2010-12-29 06:29:05 +02:00
|
|
|
|
2011-01-28 19:25:34 +02:00
|
|
|
$all_migrations = array_merge(array_keys($installed), array_keys($available));
|
2010-12-29 06:29:05 +02:00
|
|
|
|
2011-01-31 19:27:21 +02:00
|
|
|
foreach ($all_migrations as $migration)
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
|
|
|
// If this migration has since been deleted
|
2011-01-31 19:27:21 +02:00
|
|
|
if (isset($installed[$migration]) AND ! isset($available[$migration]))
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
2011-07-02 09:18:05 +03:00
|
|
|
// We should only delete a record of this migration if it does
|
2010-12-29 06:29:05 +02:00
|
|
|
// not exist in the "real world"
|
2011-01-31 19:27:21 +02:00
|
|
|
if ($installed[$migration]['applied'] === '0')
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
|
|
|
$this->_model->delete_migration($installed[$migration]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If the migration has not yet been installed :D
|
2011-01-31 19:27:21 +02:00
|
|
|
elseif ( ! isset($installed[$migration]) AND isset($available[$migration]))
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
|
|
|
$this->_model->add_migration($available[$migration]);
|
|
|
|
}
|
2011-07-02 09:18:05 +03:00
|
|
|
// Somebody changed the description of the migration, make sure we
|
2010-12-29 06:29:05 +02:00
|
|
|
// update it in the db as we use this to build the filename!
|
2011-01-31 19:27:21 +02:00
|
|
|
elseif ($installed[$migration]['description'] !== $available[$migration]['description'])
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
|
|
|
$this->_model->update_migration($installed[$migration], $available[$migration]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
2010-12-24 19:52:58 +02:00
|
|
|
}
|
|
|
|
|
2010-12-30 05:22:32 +02:00
|
|
|
/**
|
|
|
|
* Gets a database connection for running the migrations
|
|
|
|
*
|
2011-01-10 18:01:40 +02:00
|
|
|
* @param string Database connection group name
|
2010-12-30 05:22:32 +02:00
|
|
|
* @return Kohana_Database Database connection
|
|
|
|
*/
|
2011-01-10 18:01:40 +02:00
|
|
|
protected function _get_db_instance($db_group)
|
2010-12-30 05:22:32 +02:00
|
|
|
{
|
2011-01-10 18:01:40 +02:00
|
|
|
// If this isn't a dry run then just use a normal database connection
|
2011-01-31 19:27:21 +02:00
|
|
|
if ( ! $this->_dry_run)
|
2011-01-10 18:01:40 +02:00
|
|
|
return Database::instance($db_group);
|
2010-12-30 05:22:32 +02:00
|
|
|
|
|
|
|
return Minion_Migration_Database::faux_instance($db_group);
|
|
|
|
}
|
2010-12-24 19:52:58 +02:00
|
|
|
}
|