2007-09-19 00:15:17 +04:00
< ? php
/*
* $Id : Migration . php 1080 2007 - 02 - 10 18 : 17 : 08 Z jwage $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL . For more information , see
* < http :// www . phpdoctrine . com >.
*/
/**
* Doctrine_Migration
*
* this class represents a database view
*
* @ package Doctrine
2007-10-04 01:43:22 +04:00
* @ subpackage Migration
2007-09-19 00:15:17 +04:00
* @ license http :// www . opensource . org / licenses / lgpl - license . php LGPL
* @ link www . phpdoctrine . com
* @ since 1.0
* @ version $Revision : 1080 $
2007-10-04 01:43:22 +04:00
* @ author Jonathan H . Wage < jwage @ mac . com >
2007-09-19 00:15:17 +04:00
*/
class Doctrine_Migration
{
2007-10-08 19:58:23 +04:00
protected $changes = array ( 'created_tables' => array (),
'dropped_tables' => array (),
'renamed_tables' => array (),
'added_columns' => array (),
'renamed_columns' => array (),
'changed_columns' => array (),
'removed_columns' => array (),
'added_indexes' => array (),
'removed_indexes' => array ()),
$migrationTableName = 'migration_version' ,
$migrationClassesDirectory = array (),
$migrationClasses = array ();
2007-09-21 00:24:38 +04:00
2007-10-08 19:58:23 +04:00
/**
* construct
*
* Specify the path to the directory with the migration classes .
* The classes will be loaded and the migration table will be created if it does not already exist
*
* @ param string $directory
* @ return void
*/
2007-09-21 00:24:38 +04:00
public function __construct ( $directory = null )
{
if ( $directory != null ) {
$this -> migrationClassesDirectory = $directory ;
$this -> loadMigrationClasses ();
2007-10-08 19:58:23 +04:00
$this -> createMigrationTable ();
2007-09-21 00:24:38 +04:00
}
}
2007-10-08 19:58:23 +04:00
/**
* createMigrationTable
*
* Creates the migration table used to store the current version
*
* @ return void
*/
protected function createMigrationTable ()
{
$conn = Doctrine_Manager :: connection ();
try {
$conn -> export -> createTable ( $this -> migrationTableName , array ( 'version' => array ( 'type' => 'integer' , 'size' => 11 )));
return true ;
} catch ( Exception $e ) {
return false ;
}
}
/**
* loadMigrationClasses
*
* Loads the migration classes for the directory specified by the constructor
*
* @ return void
*/
2007-09-21 00:24:38 +04:00
protected function loadMigrationClasses ()
{
2007-10-08 19:58:23 +04:00
if ( $this -> migrationClasses ) {
return $this -> migrationClasses ;
}
2007-09-21 00:24:38 +04:00
$directory = $this -> migrationClassesDirectory ;
$classes = get_declared_classes ();
2007-10-08 13:00:20 +04:00
$loadedClasses = array ();
2007-09-21 00:24:38 +04:00
if ( $directory !== null ) {
foreach (( array ) $directory as $dir ) {
$it = new RecursiveIteratorIterator ( new RecursiveDirectoryIterator ( $dir ),
RecursiveIteratorIterator :: LEAVES_ONLY );
foreach ( $it as $file ) {
$e = explode ( '.' , $file -> getFileName ());
if ( end ( $e ) === 'php' && strpos ( $file -> getFileName (), '.inc' ) === false ) {
require_once $file -> getPathName ();
$requiredClass = array_diff ( get_declared_classes (), $classes );
$requiredClass = end ( $requiredClass );
$loadedClasses [ $requiredClass ] = $file -> getFileName ();
}
}
}
}
$classes = $loadedClasses ;
$parent = new ReflectionClass ( 'Doctrine_Migration' );
$loadedClasses = array ();
foreach ( $classes as $name => $fileName ) {
$class = new ReflectionClass ( $name );
while ( $class -> isSubclassOf ( $parent )) {
$class = $class -> getParentClass ();
if ( $class === false ) {
break ;
}
}
if ( $class === false ) {
continue ;
}
$loadedClasses [ $name ] = $fileName ;
}
$this -> migrationClasses = $loadedClasses ;
return $loadedClasses ;
}
2007-10-08 19:58:23 +04:00
/**
* setCurrentVersion
*
* Sets the current version in the migration table
*
* @ param string $number
* @ return void
*/
protected function setCurrentVersion ( $number )
2007-09-19 23:33:00 +04:00
{
$conn = Doctrine_Manager :: connection ();
2007-10-08 19:58:23 +04:00
if ( $this -> hasMigrated ()) {
$conn -> exec ( " UPDATE " . $this -> migrationTableName . " SET version = $number " );
2007-09-19 23:33:00 +04:00
} else {
2007-10-08 19:58:23 +04:00
$conn -> exec ( " INSERT INTO " . $this -> migrationTableName . " (version) VALUES ( $number ) " );
2007-09-19 23:33:00 +04:00
}
}
2007-10-08 19:58:23 +04:00
/**
* getCurrentVersion
*
* Get the current version of the database
*
* @ return void
*/
2007-10-08 20:04:46 +04:00
public function getCurrentVersion ()
2007-09-19 23:33:00 +04:00
{
$conn = Doctrine_Manager :: connection ();
2007-10-08 19:58:23 +04:00
$result = $conn -> fetchColumn ( " SELECT version FROM " . $this -> migrationTableName );
2007-09-19 23:33:00 +04:00
2007-10-08 19:58:23 +04:00
return isset ( $result [ 0 ]) ? $result [ 0 ] : 0 ;
2007-09-19 23:33:00 +04:00
}
2007-10-08 19:58:23 +04:00
/**
* hasMigrated
*
* Returns true / false for whether or not this database has been migrated in the past
*
* @ return void
*/
2007-10-08 20:04:46 +04:00
public function hasMigrated ()
2007-09-19 00:15:17 +04:00
{
2007-10-08 19:58:23 +04:00
$conn = Doctrine_Manager :: connection ();
2007-09-19 00:15:17 +04:00
2007-10-08 19:58:23 +04:00
$result = $conn -> fetchColumn ( " SELECT version FROM " . $this -> migrationTableName );
2007-09-19 00:15:17 +04:00
2007-10-08 19:58:23 +04:00
return isset ( $result [ 0 ]) ? true : false ;
}
/**
* getLatestVersion
*
* Gets the latest possible version from the loaded migration classes
*
* @ return void
*/
2007-10-08 20:04:46 +04:00
public function getLatestVersion ()
2007-10-08 19:58:23 +04:00
{
$this -> loadMigrationClasses ();
$versions = array ();
foreach ( $this -> migrationClasses as $name => $fileName ) {
$e = explode ( '_' , $fileName );
$version = ( int ) $e [ 0 ];
$versions [ $version ] = $version ;
2007-09-19 00:15:17 +04:00
}
2007-09-19 23:33:00 +04:00
2007-10-08 19:58:23 +04:00
rsort ( $versions );
return $versions [ 0 ];
2007-09-19 00:15:17 +04:00
}
2007-10-08 19:58:23 +04:00
/**
* getMigrationClass
*
* Get instance of migration class for $num
*
* @ param string $num
* @ return void
*/
2007-09-21 00:24:38 +04:00
protected function getMigrationClass ( $num )
2007-09-19 00:15:17 +04:00
{
2007-09-21 00:24:38 +04:00
$classes = $this -> migrationClasses ;
2007-09-19 00:15:17 +04:00
2007-09-21 00:24:38 +04:00
foreach ( $classes as $className => $fileName ) {
$e = explode ( '_' , $fileName );
$classMigrationNum = ( int ) $e [ 0 ];
2007-09-19 23:33:00 +04:00
2007-09-21 00:24:38 +04:00
if ( $classMigrationNum === $num ) {
return new $className ();
}
2007-09-19 23:33:00 +04:00
}
2007-09-21 00:24:38 +04:00
throw new Doctrine_Migration_Exception ( 'Could not find migration class for migration step: ' . $num );
2007-09-19 23:33:00 +04:00
}
2007-10-08 19:58:23 +04:00
/**
* doMigrateStep
*
* Perform migration directory for the specified version . Loads migration classes and performs the migration then processes the changes
*
* @ param string $direction
* @ param string $num
* @ return void
*/
protected function doMigrateStep ( $direction , $num )
2007-09-19 23:33:00 +04:00
{
2007-09-21 00:24:38 +04:00
$migrate = $this -> getMigrationClass ( $num );
$migrate -> doMigrate ( $direction );
2007-09-19 00:15:17 +04:00
}
2007-10-08 19:58:23 +04:00
/**
* doMigrate
*
* Perform migration for a migration class . Executes the up or down method then processes the changes
*
* @ param string $direction
* @ return void
*/
protected function doMigrate ( $direction )
2007-09-19 00:15:17 +04:00
{
if ( method_exists ( $this , $direction )) {
$this -> $direction ();
2007-10-08 19:58:23 +04:00
foreach ( $this -> changes as $type => $changes ) {
$process = new Doctrine_Migration_Process ();
$funcName = 'process' . Doctrine :: classify ( $type );
if ( ! empty ( $changes )) {
$process -> $funcName ( $changes );
}
}
2007-09-19 00:15:17 +04:00
}
}
2007-10-08 19:58:23 +04:00
/**
* migrate
*
* Perform a migration chain by specifying the $from and $to .
* If you do not specify a $from or $to then it will attempt to migrate from the current version to the latest version
*
* @ param string $from
* @ param string $to
* @ return void
*/
public function migrate ( $from = null , $to = null )
2007-09-19 00:15:17 +04:00
{
2007-10-08 19:58:23 +04:00
// If nothing specified then lets assume we are migrating from the current version to the latest version
if ( $from === null && $to === null ) {
$from = $this -> getCurrentVersion ();
$to = $this -> getLatestVersion ();
}
if ( $from === $to ) {
throw new Doctrine_Migration_Exception ( 'You specified an invalid migration path. The from and to cannot be the same. You specified from: ' . $from . ' and to: ' . $to );
2007-09-19 00:15:17 +04:00
}
2007-10-08 19:58:23 +04:00
$direction = $from > $to ? 'down' : 'up' ;
if ( $direction === 'up' ) {
for ( $i = $from + 1 ; $i <= $to ; $i ++ ) {
$this -> doMigrateStep ( $direction , $i );
}
} else {
for ( $i = $from ; $i > $to ; $i -- ) {
$this -> doMigrateStep ( $direction , $i );
}
}
$this -> setCurrentVersion ( $to );
2007-09-19 00:15:17 +04:00
}
2007-10-08 19:58:23 +04:00
/**
* addChange
*
* @ param string $type
* @ param string $array
* @ return void
*/
protected function addChange ( $type , array $change = array ())
2007-09-19 00:15:17 +04:00
{
$this -> changes [ $type ][] = $change ;
}
2007-10-08 19:58:23 +04:00
/**
* createTable
*
* @ param string $tableName
* @ param string $array
* @ param string $array
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function createTable ( $tableName , array $fields = array (), array $options = array ())
{
$options = get_defined_vars ();
$this -> addChange ( 'created_tables' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* dropTable
*
* @ param string $tableName
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function dropTable ( $tableName )
{
$options = get_defined_vars ();
$this -> addChange ( 'dropped_tables' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* renameTable
*
* @ param string $oldTableName
* @ param string $newTableName
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function renameTable ( $oldTableName , $newTableName )
{
$options = get_defined_vars ();
$this -> addChange ( 'renamed_tables' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* addColumn
*
* @ param string $tableName
* @ param string $columnName
* @ param string $type
* @ param string $array
* @ return void
*/
2007-09-19 20:26:28 +04:00
public function addColumn ( $tableName , $columnName , $type , array $options = array ())
2007-09-19 00:15:17 +04:00
{
$options = get_defined_vars ();
$this -> addChange ( 'added_columns' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* renameColumn
*
* @ param string $tableName
* @ param string $oldColumnName
* @ param string $newColumnName
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function renameColumn ( $tableName , $oldColumnName , $newColumnName )
{
$options = get_defined_vars ();
$this -> addChange ( 'renamed_columns' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* renameColumn
*
* @ param string $tableName
* @ param string $columnName
* @ param string $type
* @ param string $array
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function changeColumn ( $tableName , $columnName , $type , array $options = array ())
{
$options = get_defined_vars ();
$this -> addChange ( 'changed_columns' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* removeColumn
*
* @ param string $tableName
* @ param string $columnName
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function removeColumn ( $tableName , $columnName )
{
$options = get_defined_vars ();
$this -> addChange ( 'removed_columns' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* addIndex
*
* @ param string $tableName
* @ param string $indexName
* @ param string $array
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function addIndex ( $tableName , $indexName , array $options = array ())
{
$options = get_defined_vars ();
$this -> addChange ( 'added_indexes' , $options );
}
2007-10-08 19:58:23 +04:00
/**
* removeIndex
*
* @ param string $tableName
* @ param string $indexName
* @ return void
*/
2007-09-19 00:15:17 +04:00
public function removeIndex ( $tableName , $indexName )
{
$options = get_defined_vars ();
$this -> addChange ( 'removed_indexes' , $options );
}
}