2011-01-31 19:38:04 +02:00
|
|
|
<?php defined('SYSPATH') or die('No direct script access.');
|
2010-12-25 04:52:51 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Model for managing migrations
|
2011-01-31 19:27:21 +02:00
|
|
|
*/
|
2010-12-25 04:52:51 +02:00
|
|
|
class Model_Minion_Migration extends Model
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Database connection to use
|
|
|
|
* @var Kohana_Database
|
|
|
|
*/
|
|
|
|
protected $_db = NULL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The table that's used to store the migrations
|
|
|
|
* @var string
|
|
|
|
*/
|
2011-01-21 01:12:06 +02:00
|
|
|
protected $_table = 'minion_migrations';
|
2010-12-25 04:52:51 +02:00
|
|
|
|
|
|
|
/**
|
2011-07-02 09:18:05 +03:00
|
|
|
* Constructs the model, taking a Database connection as the first and only
|
2010-12-25 04:52:51 +02:00
|
|
|
* parameter
|
|
|
|
*
|
|
|
|
* @param Kohana_Database Database connection to use
|
|
|
|
*/
|
|
|
|
public function __construct(Kohana_Database $db)
|
|
|
|
{
|
|
|
|
$this->_db = $db;
|
|
|
|
}
|
|
|
|
|
2011-01-21 01:53:59 +02:00
|
|
|
/**
|
|
|
|
* Returns a list of migrations that are available in the filesystem
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function available_migrations()
|
|
|
|
{
|
|
|
|
$files = Kohana::list_files('migrations');
|
|
|
|
|
2011-07-02 09:18:05 +03:00
|
|
|
return $this->compile_migrations_from_files($files);
|
2011-01-21 01:53:59 +02:00
|
|
|
}
|
|
|
|
|
2011-01-21 03:18:08 +02:00
|
|
|
/**
|
2011-07-02 09:18:05 +03:00
|
|
|
* Parses a set of files generated by Kohana::find_files and compiles it
|
|
|
|
* down into an array of migrations
|
|
|
|
*
|
|
|
|
* @param array Available files
|
|
|
|
* @return array Available Migrations
|
|
|
|
*/
|
|
|
|
public function compile_migrations_from_files(array $files)
|
|
|
|
{
|
|
|
|
$migrations = array();
|
|
|
|
|
|
|
|
foreach ($files as $file => $path)
|
|
|
|
{
|
|
|
|
// If this is a directory we're dealing with
|
|
|
|
if (is_array($path))
|
|
|
|
{
|
|
|
|
$migrations += $this->compile_migrations_from_files($path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-07-02 09:30:15 +03:00
|
|
|
// Skip files without an extension of EXT
|
|
|
|
if ('.'.pathinfo($file, PATHINFO_EXTENSION) !== EXT)
|
|
|
|
continue;
|
|
|
|
|
2011-07-02 09:18:05 +03:00
|
|
|
$migration = $this->get_migration_from_filename($file);
|
|
|
|
|
|
|
|
$migrations[$migration['group'].':'.$migration['timestamp']] = $migration;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $migrations;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extracts information about a migration from its filename.
|
|
|
|
*
|
|
|
|
* Returns an array like:
|
|
|
|
*
|
|
|
|
* array(
|
|
|
|
* 'group' => 'mygroup',
|
|
|
|
* 'timestamp' => '1293214439',
|
|
|
|
* 'description' => 'initial-setup',
|
|
|
|
* 'id' => 'mygroup:1293214439'
|
|
|
|
* );
|
|
|
|
*
|
|
|
|
* @param string The migration's filename
|
|
|
|
* @return array Array of components about the migration
|
|
|
|
*/
|
|
|
|
public function get_migration_from_filename($file)
|
|
|
|
{
|
|
|
|
$migration = array();
|
|
|
|
|
|
|
|
// Get rid of the file's "migrations/" prefix, the file extension and then
|
|
|
|
// the filename itself. The "group" is essentially a slash delimited
|
|
|
|
// path from the migrations folder to the migration file
|
|
|
|
$migration['group'] = dirname(substr($file, 11, -strlen(EXT)));
|
|
|
|
|
|
|
|
if(strpos(basename($file), "_"))
|
|
|
|
{
|
|
|
|
list($migration['timestamp'], $migration['description'])
|
|
|
|
= explode('_', basename($file, EXT), 2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$migration['timestamp'] = basename($file, EXT);
|
|
|
|
$migration['description'] = "";
|
|
|
|
}
|
|
|
|
$migration['id'] = $migration['group'].':'.$migration['timestamp'];
|
|
|
|
|
|
|
|
return $migration;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets a migration file from its timestamp, description and group
|
|
|
|
*
|
|
|
|
* @param integer|array The migration's ID or an array of timestamp, description
|
|
|
|
* @param string The migration group
|
|
|
|
* @return string Path to the migration file
|
|
|
|
*/
|
|
|
|
public function get_filename_from_migration(array $migration)
|
|
|
|
{
|
|
|
|
$group = $migration['group'];
|
|
|
|
|
|
|
|
if(!empty($migration['description']))
|
|
|
|
{
|
|
|
|
$migration = $migration['timestamp'].'_'.$migration['description'];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$migration = $migration['timestamp'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$group = ( ! empty($group)) ? (rtrim($group, '/').'/') : '';
|
|
|
|
|
|
|
|
return $group.$migration.EXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Allows you to work out the class name from either an array of migration
|
|
|
|
* info, or from a migration id
|
|
|
|
*
|
|
|
|
* @param string|array The migration's ID or array of migration data
|
|
|
|
* @return string The migration class name
|
|
|
|
*/
|
|
|
|
public function get_class_from_migration($migration)
|
|
|
|
{
|
|
|
|
if (is_string($migration))
|
|
|
|
{
|
|
|
|
$migration = str_replace(array(':', '/'), ' ', $migration);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$migration = str_replace('/', ' ', $migration['group']).'_'.$migration['timestamp'];
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'Migration_'.str_replace(array(' ', '-'), '_', ucwords($migration));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks to see if the minion migrations table exists and attempts to
|
2011-01-21 03:18:08 +02:00
|
|
|
* create it if it doesn't
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function ensure_table_exists()
|
|
|
|
{
|
|
|
|
$query = $this->_db->query(Database::SELECT, "SHOW TABLES like '".$this->_table."'");
|
|
|
|
|
2011-01-31 19:27:21 +02:00
|
|
|
if ( ! count($query))
|
2011-01-21 03:18:08 +02:00
|
|
|
{
|
|
|
|
$sql = file_get_contents(Kohana::find_file('', 'minion_schema', 'sql'));
|
|
|
|
|
|
|
|
$this->_db->query(NULL, $sql);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-21 01:53:59 +02:00
|
|
|
/**
|
2011-02-17 22:43:04 +02:00
|
|
|
* Gets the status of all groups, whether they're in the db or not.
|
2011-01-21 01:53:59 +02:00
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
2011-02-17 22:43:04 +02:00
|
|
|
public function get_group_statuses()
|
2011-01-21 01:53:59 +02:00
|
|
|
{
|
2011-02-17 22:43:04 +02:00
|
|
|
// Start out using all the installed groups
|
2011-02-18 04:07:41 +02:00
|
|
|
$groups = $this->fetch_current_versions('group');
|
2011-01-21 01:53:59 +02:00
|
|
|
$available = $this->available_migrations();
|
|
|
|
|
2011-01-31 19:27:21 +02:00
|
|
|
foreach ($available as $migration)
|
2011-01-21 01:53:59 +02:00
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
if (array_key_exists($migration['group'], $groups))
|
2011-01-21 01:53:59 +02:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-02-17 22:43:04 +02:00
|
|
|
$groups[$migration['group']] = NULL;
|
2011-01-21 01:53:59 +02:00
|
|
|
}
|
|
|
|
|
2011-02-17 22:43:04 +02:00
|
|
|
return $groups;
|
2011-01-21 01:53:59 +02:00
|
|
|
}
|
|
|
|
|
2011-01-10 16:15:07 +02:00
|
|
|
/**
|
|
|
|
* Get or Set the table to use to store migrations
|
|
|
|
*
|
|
|
|
* Should only really be used during testing
|
|
|
|
*
|
|
|
|
* @param string Table name
|
|
|
|
* @return string|Model_Minion_Migration Get table name or return $this on set
|
|
|
|
*/
|
|
|
|
public function table($table = NULL)
|
|
|
|
{
|
2011-01-31 19:27:21 +02:00
|
|
|
if ($table === NULL)
|
2011-01-10 16:15:07 +02:00
|
|
|
return $this->_table;
|
|
|
|
|
|
|
|
$this->_table = $table;
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2010-12-25 04:52:51 +02:00
|
|
|
/**
|
2011-07-02 09:18:05 +03:00
|
|
|
* Creates a new select query which includes all fields in the migrations
|
|
|
|
* table plus a `id` field which is a combination of the timestamp and the
|
2010-12-25 04:52:51 +02:00
|
|
|
* description
|
|
|
|
*
|
|
|
|
* @return Database_Query_Builder_Select
|
|
|
|
*/
|
|
|
|
protected function _select()
|
|
|
|
{
|
2011-02-17 22:43:04 +02:00
|
|
|
return DB::select('*', DB::expr('CONCAT(`group`, ":", CAST(`timestamp` AS CHAR)) AS `id`'))->from($this->_table);
|
2010-12-25 04:52:51 +02:00
|
|
|
}
|
|
|
|
|
2010-12-29 06:29:05 +02:00
|
|
|
/**
|
|
|
|
* Inserts a migration into the database
|
|
|
|
*
|
|
|
|
* @param array Migration data
|
|
|
|
* @return Model_Minion_Migration $this
|
|
|
|
*/
|
|
|
|
public function add_migration(array $migration)
|
|
|
|
{
|
2011-02-17 22:43:04 +02:00
|
|
|
DB::insert($this->_table, array('timestamp', 'group', 'description'))
|
|
|
|
->values(array($migration['timestamp'], $migration['group'], $migration['description']))
|
2010-12-29 06:29:05 +02:00
|
|
|
->execute($this->_db);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2010-12-30 17:04:09 +02:00
|
|
|
/**
|
|
|
|
* Get a migration by its id
|
|
|
|
*
|
|
|
|
* @param string Migration ID
|
|
|
|
* @return array Migration info
|
|
|
|
*/
|
2011-02-17 22:43:04 +02:00
|
|
|
public function get_migration($group, $timestamp = NULL)
|
2010-12-30 17:04:09 +02:00
|
|
|
{
|
2011-01-31 19:27:21 +02:00
|
|
|
if ($timestamp === NULL)
|
2010-12-30 17:04:09 +02:00
|
|
|
{
|
2011-02-17 22:43:04 +02:00
|
|
|
if (empty($group) OR strpos(':', $group) === FALSE)
|
2010-12-30 17:04:09 +02:00
|
|
|
{
|
2011-02-17 22:43:04 +02:00
|
|
|
throw new Kohana_Exception('Invalid migration id :id', array(':id' => $group));
|
2010-12-30 17:04:09 +02:00
|
|
|
}
|
|
|
|
|
2011-02-17 22:43:04 +02:00
|
|
|
list($group, $timestamp) = explode(':', $group);
|
2010-12-30 17:04:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->_select()
|
|
|
|
->where('timestamp', '=', (string) $timestamp)
|
2011-02-17 22:43:04 +02:00
|
|
|
->where('group', '=', (string) $group)
|
2010-12-30 17:04:09 +02:00
|
|
|
->execute($this->_db)
|
|
|
|
->current();
|
|
|
|
}
|
|
|
|
|
2010-12-29 06:29:05 +02:00
|
|
|
/**
|
|
|
|
* Deletes a migration from the database
|
|
|
|
*
|
|
|
|
* @param string|array Migration id / info
|
|
|
|
* @return Model_Minion_Migration $this
|
|
|
|
*/
|
|
|
|
public function delete_migration($migration)
|
|
|
|
{
|
2011-01-31 19:27:21 +02:00
|
|
|
if (is_array($migration))
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
|
|
|
$timestamp = $migration['timestamp'];
|
2011-02-17 22:43:04 +02:00
|
|
|
$group = $migration['group'];
|
2010-12-29 06:29:05 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-17 22:43:04 +02:00
|
|
|
list($timestamp, $group) = explode(':', $migration);
|
2010-12-29 06:29:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
DB::delete($this->_table)
|
|
|
|
->where('timestamp', '=', $timestamp)
|
2011-02-17 22:43:04 +02:00
|
|
|
->where('group', '=', $group)
|
2010-12-29 06:29:05 +02:00
|
|
|
->execute($this->_db);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update an existing migration record to reflect a new one
|
|
|
|
*
|
|
|
|
* @param array The current migration
|
|
|
|
* @param array The new migration
|
|
|
|
* @return Model_Minion_Migration $this
|
|
|
|
*/
|
|
|
|
public function update_migration(array $current, array $new)
|
|
|
|
{
|
|
|
|
$set = array();
|
2011-07-02 09:18:05 +03:00
|
|
|
|
2011-01-31 19:27:21 +02:00
|
|
|
foreach ($new as $key => $value)
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
2011-01-31 19:27:21 +02:00
|
|
|
if ($key !== 'id' AND $current[$key] !== $value)
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
|
|
|
$set[$key] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-31 19:27:21 +02:00
|
|
|
if (count($set))
|
2010-12-29 06:29:05 +02:00
|
|
|
{
|
|
|
|
DB::update($this->_table)
|
|
|
|
->set($set)
|
|
|
|
->where('timestamp', '=', $current['timestamp'])
|
2011-02-17 22:43:04 +02:00
|
|
|
->where('group', '=', $current['group'])
|
2010-12-29 06:29:05 +02:00
|
|
|
->execute($this->_db);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2010-12-30 05:51:20 +02:00
|
|
|
/**
|
|
|
|
* Change the applied status for a migration
|
|
|
|
*
|
|
|
|
* @param array Migration information
|
|
|
|
* @param bool Whether this migration has been applied or unapplied
|
|
|
|
* @return Model_Minion_Migration
|
|
|
|
*/
|
|
|
|
public function mark_migration(array $migration, $applied)
|
|
|
|
{
|
|
|
|
DB::update($this->_table)
|
|
|
|
->set(array('applied' => (int) $applied))
|
|
|
|
->where('timestamp', '=', $migration['timestamp'])
|
2011-02-17 22:43:04 +02:00
|
|
|
->where('group', '=', $migration['group'])
|
2010-12-30 05:51:20 +02:00
|
|
|
->execute($this->_db);
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2010-12-25 04:52:51 +02:00
|
|
|
/**
|
|
|
|
* Selects all migrations from the migratinos table
|
|
|
|
*
|
|
|
|
* @return Kohana_Database_Result
|
|
|
|
*/
|
2010-12-29 02:46:07 +02:00
|
|
|
public function fetch_all($key = NULL, $value = NULL)
|
2010-12-25 04:52:51 +02:00
|
|
|
{
|
|
|
|
return $this->_select()
|
2010-12-29 02:46:07 +02:00
|
|
|
->execute($this->_db)
|
|
|
|
->as_array($key, $value);
|
2010-12-25 04:52:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2011-02-17 22:43:04 +02:00
|
|
|
* Fetches the latest version for all installed groups
|
2010-12-25 04:52:51 +02:00
|
|
|
*
|
2011-07-02 09:18:05 +03:00
|
|
|
* If a group does not have any applied migrations then no result will be
|
2010-12-25 04:52:51 +02:00
|
|
|
* returned for it
|
|
|
|
*
|
|
|
|
* @return Kohana_Database_Result
|
|
|
|
*/
|
2011-02-17 22:43:04 +02:00
|
|
|
public function fetch_current_versions($key = 'group', $value = NULL)
|
2010-12-25 04:52:51 +02:00
|
|
|
{
|
2010-12-28 17:40:54 +02:00
|
|
|
// Little hack needed to do an order by before a group by
|
|
|
|
return DB::select()
|
|
|
|
->from(array(
|
|
|
|
$this->_select()
|
|
|
|
->where('applied', '>', 0)
|
|
|
|
->order_by('timestamp', 'DESC'),
|
|
|
|
'temp_table'
|
|
|
|
))
|
2011-02-17 22:43:04 +02:00
|
|
|
->group_by('group')
|
2010-12-29 02:46:07 +02:00
|
|
|
->execute($this->_db)
|
|
|
|
->as_array($key, $value);
|
2010-12-25 04:52:51 +02:00
|
|
|
}
|
|
|
|
|
2010-12-31 02:49:09 +02:00
|
|
|
/**
|
2011-02-17 22:43:04 +02:00
|
|
|
* Fetches a list of groups
|
2010-12-31 02:49:09 +02:00
|
|
|
*
|
2011-07-02 09:18:05 +03:00
|
|
|
* @return array
|
2010-12-31 02:49:09 +02:00
|
|
|
*/
|
2011-02-17 22:43:04 +02:00
|
|
|
public function fetch_groups($group_as_key = FALSE)
|
2010-12-31 02:49:09 +02:00
|
|
|
{
|
|
|
|
return DB::select()
|
|
|
|
->from($this->_table)
|
2011-02-17 22:43:04 +02:00
|
|
|
->group_by('group')
|
2010-12-31 02:49:09 +02:00
|
|
|
->execute($this->_db)
|
2011-02-17 22:43:04 +02:00
|
|
|
->as_array($group_as_key ? 'group' : NULL, 'group');
|
2010-12-31 02:49:09 +02:00
|
|
|
}
|
|
|
|
|
2010-12-25 04:52:51 +02:00
|
|
|
/**
|
2011-07-02 09:18:05 +03:00
|
|
|
* Fetch a list of migrations that need to be applied in order to reach the
|
2010-12-25 04:52:51 +02:00
|
|
|
* required version
|
|
|
|
*
|
2011-02-17 22:43:04 +02:00
|
|
|
* @param string The groups to get migrations for
|
|
|
|
* @param mixed Target version
|
2010-12-25 04:52:51 +02:00
|
|
|
*/
|
2011-02-18 04:07:41 +02:00
|
|
|
public function fetch_required_migrations(array $group, $target = TRUE)
|
2010-12-25 04:52:51 +02:00
|
|
|
{
|
2011-02-18 01:53:15 +02:00
|
|
|
$migrations = array();
|
|
|
|
$current_groups = $this->fetch_groups(TRUE);
|
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
// Make sure the group(s) exist
|
|
|
|
foreach ($group as $group_name)
|
2011-02-18 01:53:15 +02:00
|
|
|
{
|
|
|
|
if ( ! isset($current_groups[$group_name]))
|
|
|
|
{
|
|
|
|
throw new Kohana_Exception("Migration group :group does not exist", array(':group' => $group_name));
|
|
|
|
}
|
|
|
|
}
|
2010-12-25 04:52:51 +02:00
|
|
|
|
2011-02-17 22:43:04 +02:00
|
|
|
$query = $this->_select();
|
2010-12-25 04:52:51 +02:00
|
|
|
|
2011-02-17 22:43:04 +02:00
|
|
|
if (is_bool($target))
|
2010-12-30 05:42:03 +02:00
|
|
|
{
|
2011-02-18 01:53:15 +02:00
|
|
|
$up = $target;
|
|
|
|
|
2011-02-17 22:43:04 +02:00
|
|
|
// If we want to limit this migration to certain groups
|
2011-02-18 04:07:41 +02:00
|
|
|
if ( ! empty($group))
|
2010-12-25 05:12:18 +02:00
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
if (count($group) > 1)
|
2010-12-28 05:29:57 +02:00
|
|
|
{
|
2011-02-17 22:43:04 +02:00
|
|
|
$query->where('group', 'IN', $group);
|
2010-12-28 05:29:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
$query->where('group', '=', $group[0]);
|
2010-12-28 05:29:57 +02:00
|
|
|
}
|
2010-12-25 05:12:18 +02:00
|
|
|
}
|
2011-02-18 01:53:15 +02:00
|
|
|
}
|
2011-02-18 04:07:41 +02:00
|
|
|
// Relative up/down target
|
|
|
|
elseif (in_array($target[0], array('+', '-')))
|
2011-02-18 01:53:15 +02:00
|
|
|
{
|
|
|
|
list($target, $up) = $this->resolve_target($group, $target);
|
|
|
|
|
|
|
|
$query->where('group', '=', $group);
|
2011-02-17 22:43:04 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
if( $target !== NULL)
|
|
|
|
{
|
|
|
|
if ($up)
|
|
|
|
{
|
|
|
|
$query->where('timestamp', '<=', $target);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$query->where('timestamp', '>=', $target);
|
|
|
|
}
|
|
|
|
}
|
2011-07-02 09:18:05 +03:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
}
|
|
|
|
// Absolute timestamp
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$query->where('group', '=', $group);
|
|
|
|
|
2011-03-02 23:30:30 +02:00
|
|
|
$statuses = $this->fetch_current_versions('group', 'timestamp');
|
|
|
|
$up = (empty($statuses) OR ($statuses[$group[0]] < $target));
|
2011-02-18 04:07:41 +02:00
|
|
|
|
2011-03-02 23:30:30 +02:00
|
|
|
if ($up)
|
2011-02-17 22:43:04 +02:00
|
|
|
{
|
2011-02-18 01:53:15 +02:00
|
|
|
$query->where('timestamp', '<=', $target);
|
2011-02-17 22:43:04 +02:00
|
|
|
}
|
2010-12-25 05:12:18 +02:00
|
|
|
else
|
2010-12-25 04:52:51 +02:00
|
|
|
{
|
2011-02-18 01:53:15 +02:00
|
|
|
$query->where('timestamp', '>', $target);
|
2010-12-25 04:52:51 +02:00
|
|
|
}
|
2011-02-17 22:43:04 +02:00
|
|
|
}
|
2011-07-02 09:18:05 +03:00
|
|
|
|
2011-02-18 01:53:15 +02:00
|
|
|
// If we're migrating up
|
|
|
|
if ($up)
|
|
|
|
{
|
|
|
|
$query
|
|
|
|
->where('applied', '=', 0)
|
|
|
|
->order_by('timestamp', 'ASC');
|
|
|
|
}
|
|
|
|
// If we're migrating down
|
2011-02-17 22:43:04 +02:00
|
|
|
else
|
|
|
|
{
|
2011-02-18 01:53:15 +02:00
|
|
|
$query
|
2011-02-18 04:07:41 +02:00
|
|
|
->where('applied', '=', 1)
|
2011-02-18 01:53:15 +02:00
|
|
|
->order_by('timestamp', 'DESC');
|
|
|
|
}
|
2010-12-25 04:52:51 +02:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
return array($query->execute($this->_db)->as_array(), $up);
|
2011-02-18 01:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolve a (potentially relative) target for a group to a definite timestamp
|
|
|
|
*
|
|
|
|
* @param string Group name
|
|
|
|
* @param string|int Target
|
|
|
|
* @return array First element timestamp, second is boolean (TRUE if up, FALSE if down)
|
|
|
|
*/
|
|
|
|
public function resolve_target($group, $target)
|
|
|
|
{
|
|
|
|
if (empty($group))
|
|
|
|
{
|
|
|
|
throw new Kohana_Exception("No group specified");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_array($group))
|
|
|
|
{
|
|
|
|
if (count($group) > 1)
|
|
|
|
{
|
|
|
|
throw new Kohana_Exception("A target can only be expressed for a single group");
|
|
|
|
}
|
|
|
|
|
|
|
|
$group = $group[0];
|
|
|
|
}
|
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
if( ! in_array($target[0], array('+', '-')))
|
|
|
|
{
|
|
|
|
throw new Kohana_Exception("Invalid relative target");
|
|
|
|
}
|
|
|
|
|
2011-02-18 01:53:15 +02:00
|
|
|
$query = $this->_select();
|
|
|
|
$statuses = $this->fetch_current_versions();
|
|
|
|
$target = (string) $target;
|
|
|
|
$group_applied = isset($statuses[$group]);
|
|
|
|
$timestamp = $group_applied ? $statuses[$group]['timestamp'] : NULL;
|
2011-02-18 04:07:41 +02:00
|
|
|
$amount = substr($target, 1);
|
|
|
|
$up = $target[0] === '+';
|
2011-07-02 09:18:05 +03:00
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
if ($up)
|
2011-02-18 01:53:15 +02:00
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
if ($group_applied)
|
2011-02-17 22:43:04 +02:00
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
$query->where('timestamp', '>', $timestamp);
|
2011-02-17 22:43:04 +02:00
|
|
|
}
|
2010-12-25 04:52:51 +02:00
|
|
|
}
|
2011-02-18 01:53:15 +02:00
|
|
|
else
|
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
if ( ! $group_applied)
|
2011-02-18 01:53:15 +02:00
|
|
|
{
|
2011-02-18 04:07:41 +02:00
|
|
|
throw new Kohana_Exception(
|
2011-07-02 09:18:05 +03:00
|
|
|
"Cannot migrate group :group down as none of its migrations have been applied",
|
2011-02-18 04:07:41 +02:00
|
|
|
array(':group' => $group)
|
|
|
|
);
|
2011-02-18 01:53:15 +02:00
|
|
|
}
|
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
$query
|
|
|
|
->where('applied', '=', 1)
|
|
|
|
->where('timestamp', '<=', $timestamp);
|
2011-02-18 01:53:15 +02:00
|
|
|
}
|
|
|
|
|
2011-02-18 04:07:41 +02:00
|
|
|
$query->limit($amount);
|
2011-02-18 01:53:15 +02:00
|
|
|
|
|
|
|
$query->where('group', '=', $group);
|
|
|
|
|
|
|
|
$query->order_by('timestamp', ($up ? 'ASC' : 'DESC'));
|
|
|
|
|
|
|
|
$results = $query->execute($this->_db);
|
|
|
|
|
|
|
|
if ($amount !== NULL AND count($results) != $amount)
|
|
|
|
{
|
|
|
|
return array(NULL, $up);
|
|
|
|
}
|
|
|
|
|
2011-05-12 22:52:00 +03:00
|
|
|
// Seek to the requested row
|
|
|
|
for ($i = 0; $i < $amount - 1; $i++)
|
|
|
|
{
|
|
|
|
$results->next();
|
|
|
|
}
|
|
|
|
|
|
|
|
return array((string) $results->get('timestamp'), $up);
|
2010-12-25 04:52:51 +02:00
|
|
|
}
|
|
|
|
}
|