日期:2014-05-16  浏览次数:20618 次

实现简单的 DB 迁移管理
<?php
Core_Autoloader::loadFile(COREPATH . '/vendor/SingleTableCRUD.class.php',true);

/**
 * 迁移操作入口
 *
 * @package pkg
 *
 */
class Pkg_Gen_Table_Migration {

	private static $migrationTable = 'sql_table_migration';

	/**
	 * @var Pkg_Gen_Table_MigrationLog
	 */
	static $logger = null;
	
	/**
	 * @return TplEngine
	 */
	private static function getTplEngine(){
		static $tplEngine = null;
		if (!$tplEngine){
			Core_Autoloader::loadFile(COREPATH . '/vendor/TplEngine.class.php');

			$tplConfig = array(
				'templateDir' => dirname(__FILE__) . '/_views',
				'enableCache' => false,
			);
			$tplEngine = new TplEngine($tplConfig);
		}
		return $tplEngine;
	}

	private static function getMigrations($migrationDir,$tableClassPrefix){
		static $migrations = null;
		if ($migrations) return $migrations;

		$migrations = array();
		$index = 1;
		// 获取迁移类对象
		foreach (glob("{$migrationDir}/*.php") as $filename) {
			$id = basename($filename,'.php');
			$className = "{$tableClassPrefix}{$id}";
			// 加载迁移类到系统
			Core_Autoloader::loadClass($className);

			$obj = new $className();
			// 校验迁移类是否实现了Pkg_Gen_Table_MigrationElement接口
			if ( !($obj instanceof Pkg_Gen_Table_MigrationElement) ){
				throw new Core_Exception_TypeMismatch('迁移类对象','Pkg_Gen_Table_MigrationElement',$className);
			}

			$migrations[$index] = array('id' =>$id,'class' => $className ,'instance' => $obj);
			$index ++;
		}

		return $migrations;
	}

	private static function initMigrationTable(Core_DB $dbo){
		static $is = false;
		if (!$is){
			$row = $dbo->getRow( sprintf("SHOW TABLES LIKE '%s'",self::$migrationTable) );
			if (!empty($row)){
				$is = true;
				return;
			}
			$tb = Pkg_Gen_Table_DML::newInstance($dbo,self::$migrationTable);

			$tb->struct(array(
				$tb->combindColumnParams('version','int',true,6),
			))
			->setPrimaryKey('version')
			->setOptions(array(
				Pkg_Gen_Table_DML::ENGINE => Pkg_Gen_Table_DML::ENGINE_INNODB,

			))->create();

			$tb->execute();
			$is = SingleTableCRUD::insert(self::$migrationTable,array('version'=>0));
			self::$logger->append($dbo->lastsql);
		}
	}

	static function ls(Core_DB $dbo,$migrationDir,$tableClassPrefix,$saveUrl){

		if ( !(is_readable($migrationDir) && is_dir($migrationDir)) )
			throw new Exception("无效的迁移类文件存放路径: {$migrationDir}");

		self::initMigrationTable($dbo);
		$migrations = self::getMigrations($migrationDir,$tableClassPrefix);

		// 得到当前版本号,缺省为0
		$curversion = (int) $dbo->getOne(sprintf('select version from %s',self::$migrationTable));

		self::getTplEngine()->assign('database',$dbo->getDSN('database'));
		self::getTplEngine()->assign('migrations',$migrations);
		self::getTplEngine()->assign('version',$curversion);
		self::getTplEngine()->assign('saveurl',$saveUrl);
		self::getTplEngine()->display('migrations.php');
	}

	static function change(Core_DB $dbo,$migrationDir,$tableClassPrefix,$newversion,$lastversion){

		if ( !(is_readable($migrationDir) && is_dir($migrationDir)) )
			throw new Exception("无效的迁移类文件存放路径: {$migrationDir}");

		self::initMigrationTable($dbo);
		$migrations = self::getMigrations($migrationDir,$tableClassPrefix);

		// 得到当前版本号,缺省为0
		$curversion = (int) $dbo->getOne(sprintf('select version from %s',self::$migrationTable));

		if ($curversion != $lastversion) throw new Exception("无效的参数 lastversion: {$lastversion}");

		if ($curversion == $newversion) throw new Exception("版本无需迁移操作");
		
		if ($newversion > 0){
			if (!isset($migrations[$newversion])) throw new Exception("无效的参数 newversion: {$newversion}");
		}
		
		// 开始进行版本迁移操作
		if ($curversion > $newversion){
			// 反向
			for($start=$curversion,$end = $newversion; $start > $end; $start --){
				$instance = $migrations[$start]['instance'];
				/* @var $instance Pkg_Gen_Table_MigrationElement */
				self::$logger->append($migrations[$start]['class'] . '::down()');
				try {