Changeset 10225
- Timestamp:
- 07/11/08 20:29:49 (4 months ago)
- Files:
-
- plugins/sfPropelMigrationsLightPlugin/trunk/LICENSE (modified) (1 diff, 1 prop)
- plugins/sfPropelMigrationsLightPlugin/trunk/README (modified) (5 diffs, 1 prop)
- plugins/sfPropelMigrationsLightPlugin/trunk/data/tasks/sfPakePropelMigrationsLight.php (modified) (7 diffs, 2 props)
- plugins/sfPropelMigrationsLightPlugin/trunk/lib/sfMigration.class.php (modified) (13 diffs, 2 props)
- plugins/sfPropelMigrationsLightPlugin/trunk/lib/sfMigrator.class.php (modified) (7 diffs, 2 props)
- plugins/sfPropelMigrationsLightPlugin/trunk/lib/task (added)
- plugins/sfPropelMigrationsLightPlugin/trunk/lib/task/sfPropelInitMigrationTask.class.php (added)
- plugins/sfPropelMigrationsLightPlugin/trunk/lib/task/sfPropelMigrateTask.class.php (added)
- plugins/sfPropelMigrationsLightPlugin/trunk/package-sfPropelMigrationsLightPlugin.xml (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
plugins/sfPropelMigrationsLightPlugin/trunk/LICENSE
- Property svn:eol-style set to native
r5481 r10225 1 Copyright (c) 2006-200 7Martin Kreidenweis1 Copyright (c) 2006-2008 Martin Kreidenweis 2 2 3 3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: plugins/sfPropelMigrationsLightPlugin/trunk/README
- Property svn:eol-style set to native
r9213 r10225 8 8 9 9 This plugins is called "light", because it doesn't do any RDBMS-abstraction. So you'll have to manually write SQL code. It currently works quite alright for me, though. And you don't have to write all the SQL code manually of course. Actually you'll just make a {{{diff}}} of the {{{schema.sql}}} file created by propel and copy'n'paste the right parts of it in a new migration file. 10 10 11 I think something more general is planned for [http://propel.phpdb.org/trac/wiki/Development/Roadmap Propel 2.0]. 11 12 12 13 13 == Installation == … … 24 24 25 25 === step one -- create migration === 26 26 27 The plugin provides an {{{init-migration}}} task. So run {{{php symfony init-migration migration_name}}}. This will generate a new migration class stub in the migrations directory. The migration name is purely informational. I doesn't have to be unique. 27 28 … … 49 50 }}} 50 51 52 For the special case of your first migration, the plugin will write the migration for you, using all `*.sql` files that have been automatically generated by Propel. 53 51 54 === step two -- run the migration === 52 55 To actually update the database you have to run the {{{migrate}}} task. … … 58 61 (So put a call to it in your upgrade script if you have one.) 59 62 There's no harm done by calling the migrate task even if no migrations have been added. It just won't do anything. 60 61 63 62 64 == More Information == … … 77 79 Then, in {{{Migration042::up()}}} you'd write {{{$this->loadFixtures();}}} at some point and it will load all the YAML files in the "042" directory. 78 80 79 80 81 == Changelog == 81 82 83 === 2008-07-11 | 1.1.0 (Kris.Wallsmith) === 84 85 * Added symfony 1.1 tasks 86 * Added auto-generation of first migration 87 * Added `->loadSql()` method to run SQL from a file 88 * Coding standards fixes 89 82 90 === 2008-05-23 | 1.0.1 === 83 * develop7: fixed syntax error in sfMigration::addColumn() 84 91 92 * develop7: fixed syntax error in sfMigration::addColumn() 93 85 94 === 2007-10-12 | 0.5.0 Beta === 86 95 87 96 Finally released as a plugin. This is my first plugin, hope everything works... 88 97 Comments welcome. :) 89 90 98 91 99 === 2007-09-07 === plugins/sfPropelMigrationsLightPlugin/trunk/data/tasks/sfPakePropelMigrationsLight.php
- Property svn:eol-style set to native
- Property svn:keywords set to Id
r5736 r10225 1 1 <?php 2 2 3 /* 3 4 * This file is part of the sfPropelMigrationsLightPlugin package. 4 * (c) 2006-200 7Martin Kreidenweis <sf@kreidenweis.com>5 * 5 * (c) 2006-2008 Martin Kreidenweis <sf@kreidenweis.com> 6 * 6 7 * For the full copyright and license information, please view the LICENSE 7 8 * file that was distributed with this source code. … … 9 10 10 11 /** 12 * Symfony 1.0 tasks for sfPropelMigrationsLightPlugin. 13 * 11 14 * @package symfony 12 15 * @subpackage plugin … … 25 28 if (count($args) == 0) 26 29 { 27 throw new Exception('You must provide a migration name.');30 throw new sfException('You must provide a migration name.'); 28 31 } 29 32 30 if ($args[0])33 if ($args[0]) 31 34 { 32 35 $migrator = new sfMigrator(); 33 36 34 37 if (!is_dir($migrator->getMigrationsDir())) 35 38 { 36 39 pake_mkdirs($migrator->getMigrationsDir()); 37 40 } 38 39 pake_echo_action( "migrations", "generating new migration stub");41 42 pake_echo_action('migrations', 'generating new migration stub'); 40 43 $filename = $migrator->generateMigration($args[0]); 41 pake_echo_action( "file+", $filename);44 pake_echo_action('file+', $filename); 42 45 } 43 46 } 44 45 47 46 48 function run_migrate($task, $args) … … 48 50 if (count($args) == 0) 49 51 { 50 throw new Exception('You must provide a app.');52 throw new sfException('You must provide a app.'); 51 53 } 52 54 … … 61 63 define('SF_ROOT_DIR', sfConfig::get('sf_root_dir')); 62 64 define('SF_APP', $app); 63 define('SF_ENVIRONMENT', ($env)?$env:'cli');65 define('SF_ENVIRONMENT', $env ? $env : 'cli'); 64 66 define('SF_DEBUG', true); 65 67 … … 70 72 $databaseManager->initialize(); 71 73 72 73 74 $migrator = new sfMigrator(); 74 75 75 76 // if no other arguments besides app, then migrate to latest version 76 77 if (count($args) == 1) … … 78 79 $runMigrationsCount = $migrator->migrate(); 79 80 } 80 elseif (isset($args[1]) && preg_match('/^\d+$/',$args[1]))81 elseif (isset($args[1]) && ctype_digit($args[1])) 81 82 { 82 $runMigrationsCount = $migrator->migrate( (int)$args[1]);83 $runMigrationsCount = $migrator->migrate($args[1]); 83 84 } 84 85 else 85 86 { 86 throw new Exception("You can provide a destination migration number as a second parameter");87 throw new sfException('You can provide a destination migration number as a second parameter'); 87 88 } 88 89 89 90 $currentVersion = $migrator->getCurrentVersion(); 90 91 pake_echo_action( "migrations", "migrated ".$runMigrationsCount." step(s)");92 pake_echo_action( "migrations", "current database version: ".$currentVersion);91 92 pake_echo_action('migrations', 'migrated '.$runMigrationsCount.' step(s)'); 93 pake_echo_action('migrations', 'current database version: '.$currentVersion); 93 94 } plugins/sfPropelMigrationsLightPlugin/trunk/lib/sfMigration.class.php
- Property svn:eol-style set to native
- Property svn:keywords set to Id
r9603 r10225 1 1 <?php 2 2 3 /* 3 4 * This file is part of the sfPropelMigrationsLightPlugin package. 4 * (c) 2006-200 7Martin Kreidenweis <sf@kreidenweis.com>5 * 5 * (c) 2006-2008 Martin Kreidenweis <sf@kreidenweis.com> 6 * 6 7 * For the full copyright and license information, please view the LICENSE 7 8 * file that was distributed with this source code. … … 9 10 10 11 /** 11 * Base class for all Migrations12 * 12 * Base class for all migrations. 13 * 13 14 * @package symfony 14 15 * @subpackage plugin … … 18 19 abstract class sfMigration 19 20 { 20 private $migrator = null; 21 private $migrationNumber = null; 22 23 /** 24 * constructor 25 * 26 * @param sfMigrator $migrator the migrator instance calling this migration 27 * @param int $migrationNumber the DB version the migration (up) will migrates to 21 protected 22 $migrator = null, 23 $migrationNumber = null; 24 25 /** 26 * Constructor. 27 * 28 * @param sfMigrator $migrator The migrator instance calling this migration 29 * @param integer $migrationNumber The DB version the migration (up) will migrate to 28 30 */ 29 31 public function __construct(sfMigrator $migrator, $migrationNumber) … … 32 34 $this->migrationNumber = $migrationNumber; 33 35 } 34 35 /** 36 * returns the migrator instance that called the migration37 * 36 37 /** 38 * Get the migrator instance that called this migration. 39 * 38 40 * @return sfMigrator 39 41 */ … … 42 44 return $this->migrator; 43 45 } 44 45 /** 46 * returns the Propel connection47 * 48 * @return Connection46 47 /** 48 * Get the Propel connection. 49 * 50 * @return mixed 49 51 */ 50 52 protected function getConnection() … … 52 54 return Propel::getConnection(); 53 55 } 54 55 /** 56 * returns the migration number of this migration 57 * 58 * @param mixed $formatted if true the result is a zero-padded string, otherwise an int is returned 59 * @return mixed 56 57 /** 58 * Get the migration number of this migration. 59 * 60 * @param boolean $formatted If true the result is a zero-padded string, otherwise an integer is returned 61 * 62 * @return mixed 60 63 */ 61 64 protected function getMigrationNumber($formatted = true) 62 65 { 63 if ($formatted) 64 { 65 return sprintf("%03d", $this->migrationNumber); 66 } 67 else 68 { 69 return (int)$this->migrationNumber; 70 } 71 } 72 73 /** 74 * Executes a SQL statement, returns the number of affected rows 75 * 76 * @param string $sql the SQL code to execute 77 * @return number of affected rows 78 * @throws SQLException 79 */ 80 protected final function executeSQL($sql) 66 return $formatted ? sprintf('%03d', $this->migrationNumber) : (int) $this->migrationNumber; 67 } 68 69 /** 70 * Execute a SQL statement. 71 * 72 * @param string $sql the SQL code to execute 73 * 74 * @return integer Number of affected rows 75 */ 76 protected function executeSQL($sql) 81 77 { 82 78 return sfMigrator::executeUpdate($sql); … … 84 80 85 81 /** 86 * Execute s the SQL query and returns the resultset.87 * 88 * @param string $sql The SQL statement.89 * @param int$fetchmode90 * @return object ResultSet91 * @ throws SQLException if a database access error occurs.92 */ 93 protected f inal function executeQuery($sql, $fetchmode = null)82 * Execute a SQL query. 83 * 84 * @param string $sql The SQL statement. 85 * @param integer $fetchmode 86 * 87 * @return mixed 88 */ 89 protected function executeQuery($sql, $fetchmode = null) 94 90 { 95 91 return sfMigrator::executeQuery($sql, $fetchmode); … … 97 93 98 94 /** 99 * Add s a column to an existing table95 * Add a column to an existing table. 100 96 * 101 97 * @param string $table the table name … … 107 103 protected function addColumn($table, $column, $type, $notNull = false, $default = null) 108 104 { 109 $sql = "ALTER TABLE $table ADD COLUMN $column $type"; 110 if ($notNull) { 111 $sql .= " NOT NULL"; 112 } 113 if ($default !== null) { 114 if (!is_int($default)) { 115 $default = "'" . $default . "'"; 105 $sql = sprintf('ALTER TABLE %s ADD COLUMN %s %s', $table, $column, $type); 106 107 if ($notNull) 108 { 109 $sql .= ' NOT NULL'; 110 } 111 112 if (!is_null($default)) 113 { 114 if (!ctype_digit($default)) 115 { 116 $default = '"'.$default.'"'; 116 117 } 117 $sql .= " DEFAULT $default"; 118 } 119 120 return self::executeSQL($sql); 118 119 $sql .= ' DEFAULT '.$default; 120 } 121 122 return $this->executeSQL($sql); 121 123 } 122 124 123 125 /** 124 126 * Loads the fixture files of the migration. 127 * 125 128 * Has to be called manually. 126 * 127 * Be careful. Due to the nature Propel and fixture-loading works you'll probably get problems 128 * when you change the definitions of affected tables in later migrations. 129 * 130 * @param bool $deleteOldRecords whether the affected tables' content should be deleted prior to loading the fixtures, default: false 129 * 130 * Be careful. Due to the nature Propel and fixture-loading works you'll 131 * probably get problems when you change the definitions of affected tables 132 * in later migrations. 133 * 134 * @param boolean $deleteOldRecords Whether the affected tables' content should be deleted prior to loading the fixtures, default: false 131 135 */ 132 136 protected function loadFixtures($deleteOldRecords = false) 133 137 { 134 $fixturesDir = $this->getMigrator()->getMigrationsFixturesDir() . DIRECTORY_SEPARATOR .$this->getMigrationNumber();135 138 $fixturesDir = $this->getMigrator()->getMigrationsFixturesDir().DIRECTORY_SEPARATOR.$this->getMigrationNumber(); 139 136 140 if (!is_dir($fixturesDir)) 137 141 { 138 throw new sfException( "no fixtures exist for migration " .$this->getMigrationNumber());139 } 140 142 throw new sfException('No fixtures exist for migration '.$this->getMigrationNumber()); 143 } 144 141 145 $data = new sfPropelData(); 142 146 $data->setDeleteCurrentData($deleteOldRecords); … … 145 149 146 150 /** 147 * begins a transaction 151 * Execute SQL from a file. 152 * 153 * @param string $file Path to the SQL file 154 */ 155 protected function loadSql($file) 156 { 157 if (!is_readable($file)) 158 { 159 throw new sfException(sprintf('The SL file %s does not exist or is not readable.', $file)); 160 } 161 162 foreach (explode(';', file_get_contents($file)) as $query) 163 { 164 if (trim($query)) 165 { 166 $this->executeQuery($query); 167 } 168 } 169 } 170 171 /** 172 * Begin a transaction. 148 173 */ 149 174 protected function begin() 150 175 { 151 $this->getConnection()->begin(); 152 } 153 154 /** 155 * commits transaction 176 $con = $this->getConnection(); 177 178 $con instanceof PropelPDO ? $con->beginTransaction() : $con->begin(); 179 } 180 181 /** 182 * Commit a transaction. 156 183 */ 157 184 protected function commit() … … 161 188 162 189 /** 163 * rolls back transaction190 * Rollback a transaction. 164 191 */ 165 192 protected function rollback() … … 169 196 170 197 /** 171 * output some diagnostic or informational message 198 * Output some diagnostic or informational message. 199 * 200 * @param string $text 172 201 */ 173 202 protected function diag($text) … … 178 207 179 208 /** 180 * bring the Database Schema up to the current Version from the previous one209 * Migrate the schema up, from the previous version to the current one. 181 210 */ 182 211 abstract public function up(); 183 212 184 213 /** 185 * bringthe schema down to the previous version, i.e. undo the modifications made in up()214 * Migrate the schema down to the previous version, i.e. undo the modifications made in up() 186 215 */ 187 216 abstract public function down(); plugins/sfPropelMigrationsLightPlugin/trunk/lib/sfMigrator.class.php
- Property svn:eol-style set to native
- Property svn:keywords set to Id
r6149 r10225 1 1 <?php 2 2 3 /* 3 4 * This file is part of the sfPropelMigrationsLightPlugin package. 4 * (c) 2006-200 7Martin Kreidenweis <sf@kreidenweis.com>5 * 5 * (c) 2006-2008 Martin Kreidenweis <sf@kreidenweis.com> 6 * 6 7 * For the full copyright and license information, please view the LICENSE 7 8 * file that was distributed with this source code. 8 9 */ 9 10 10 11 11 /** 12 * manages all calls to the sfMigration class instances12 * Manage all calls to the sfMigration class instances. 13 13 * 14 14 * @package symfony … … 20 20 { 21 21 /** 22 * string array of migration files' names23 * 22 * Migration filenames. 23 * 24 24 * @var array $migrations 25 25 */ 26 private $migrations = array(); 27 26 protected $migrations = array(); 27 28 /** 29 * Perform an update on the database. 30 * 31 * @param string $sql 32 * 33 * @return integer 34 */ 35 static public function executeUpdate($sql) 36 { 37 $con = Propel::getConnection(); 38 39 return $con instanceof PropelPDO ? $con->exec($sql) : $con->executeUpdate($sql); 40 } 41 42 /** 43 * Perform a query on the database. 44 * 45 * @param string $sql 46 * @param string $fetchmode 47 * 48 * @return mixed 49 */ 50 static public static function executeQuery($sql, $fetchmode = null) 51 { 52 $con = Propel::getConnection(); 53 54 if ($con instanceof PropelPDO) 55 { 56 $stmt = $con->prepare($sql); 57 $stmt->execute(); 58 59 return $stmt; 60 } 61 else 62 { 63 return $con->executeQuery($sql, $fetchmode); 64 } 65 } 66 67 /** 68 * Constructor. 69 */ 28 70 public function __construct() 29 71 { … … 32 74 33 75 /** 34 * does all the migrating 35 * 36 * @param int $destVersion version number to migrate to, default: migrates to max existing 37 * @return int number of executed migrations 76 * Execute migrations. 77 * 78 * @param integer $destVersion Version number to migrate to, defaults to 79 * the max existing 80 * 81 * @return integer Number of executed migrations 38 82 */ 39 83 public function migrate($destVersion = null) 40 84 { 41 85 $maxVersion = $this->getMaxVersion(); 42 if ($destVersion === null) 86 if ($destVersion === null) 43 87 { 44 88 $destVersion = $maxVersion; … … 46 90 else 47 91 { 48 $destVersion = (int)$destVersion; 92 $destVersion = (int) $destVersion; 93 49 94 if (($destVersion > $maxVersion) || ($destVersion < 0)) 50 95 { 51 throw new sfException( "Migration $destVersion does not exist.");52 } 53 } 54 96 throw new sfException(sprintf('Migration %d does not exist.', $destVersion)); 97 } 98 } 99 55 100 $sourceVersion = $this->getCurrentVersion(); 56 101 57 102 // do appropriate stuff according to migration direction 58 103 if ($destVersion == $sourceVersion) … … 60 105 return 0; 61 106 } 62 else if ($destVersion < $sourceVersion)107 elseif ($destVersion < $sourceVersion) 63 108 { 64 109 $res = $this->migrateDown($sourceVersion, $destVersion); 65 110 } 66 else 67 { 68 $res = $this->migrateUp($sourceVersion, $destVersion); 69 } 70 111 else 112 { 113 $res = $this->migrateUp($sourceVersion, $destVersion); 114 } 115 71 116 return $res; 72 117 } 73 74 /** 75 * Generates a new, emtpy migration stub 76 * 77 * @param string $name name of the new migration 78 * @return string filename of the new migration file 118 119 /** 120 * Generate a new migration stub 121 * 122 * @param string $name Name of the new migration 123 * 124 * @return string Filename of the new migration file 79 125 */ 80 126 public function generateMigration($name) 81 127 { 82 $template = "<?php83 84 class %MigrationClassName% extends sfMigration {85 public function up()86 {87 88 }89 90 public function down()91 {92 93 }94 }95 ";96 97 128 // calculate version number for new migration 98 $maxVersion = (int)$this->getMaxVersion(); 99 $newVersion = sprintf("%03d", $maxVersion + 1); 100 101 // generate new migration class stub 102 $newClass = str_replace('%MigrationClassName%', 'Migration'.$newVersion, $template); 103 129 $maxVersion = sprintf('%03d', $this->getMaxVersion()); 130 $newVersion = sprintf('%03d', $maxVersion + 1); 131 104 132 // sanitize name 105 133 $name = preg_replace('/[^a-zA-Z0-9]/', '_', $name); 106 134 135 $upLogic = ''; 136 $downLogic = ''; 137 138 if ('001' == $newVersion) 139 { 140 $this->generateFirstMigrationLogic($name, $newVersion, $upLogic, $downLogic); 141 } 142 143 $newClass = <<<EOF 144 <?php 145 146 /** 147 * Migrations between versions $maxVersion and $newVersion. 148 */ 149 class Migration$newVersion extends sfMigration 150 { 151 /** 152 * Migrate up to version $newVersion. 153 */ 154 public function up() 155 { 156 $upLogic 157 } 158 159 /** 160 * Migrate down to version $maxVersion. 161 */ 162 public function down() 163 { 164 $downLogic 165 } 166 } 167 168 EOF; 169 107 170 // write new migration stub 108 171 $newFileName = $this->getMigrationsDir().DIRECTORY_SEPARATOR.$newVersion.'_'.$name.'.php'; 109 172 file_put_contents($newFileName, $newClass); 110 173 111 174 return $newFileName; 112 175 } 113 114 /** 115 * Writes the given version as current version to the database 176 177 /** 178 * Get the list of migration filenames. 179 * 180 * @return array 181 */ 182 public function getMigrations() 183 { 184 return $this->migrations; 185 } 186 187 /** 188 * @return integer The lowest migration that exists 189 */ 190 public function getMinVersion() 191 { 192 return $this->migrations ? $this->getMigrationNumberFromFile($this->migrations[0]) : 0; 193 } 194 195 /** 196 * @return integer The highest existing migration that exists 197 */ 198 public function getMaxVersion() 199 { 200 $count = count($this->migrations); 201 202 return $count ? $this->getMigrationNumberFromFile($this->migrations[$count - 1]) : 0; 203 } 204 205 /** 206 * Get the current schema version from the database. 207 * 208 * If no schema version is currently stored in the database, one is created 209 * and initialized with 0. 116 210 * 117 * @param int $version new current version 118 */ 119 protected function setCurrentVersion($version) 120 { 121 $version = (int)$version; 122 123 self::executeUpdate("UPDATE schema_info SET version = $version"); 124 } 125 126 /** 127 * migrates down from version $from to version $to 128 * 129 * @param int $from 130 * @param int $to 131 * @return int number of executed migrations 132 */ 133 protected function migrateDown($from, $to) 134 { 135 $con = Propel::getConnection(); 136 $counter = 0; 137 138 // iterate over all needed migrations 139 for ($i = $from; $i > $to; $i--) 140 { 141 if ($con instanceof PropelPDO) { 142 $con->beginTransaction(); 143 } else { 144 $con->begin(); 145 } 146 try 147 { 148 $migration = $this->getMigrationObject($i); 149 $migration->down(); 150 151 $this->setCurrentVersion($i-1); 152 153 $con->commit(); 154 } 155 catch (Exception $e) 156 { 157 $con->rollback(); 158 throw $e; 159 } 160 161 $counter++; 162 } 163 164 return $counter; 165 } 166 167 /** 168 * migrates up from version $from to version $to 169 * 170 * @param int $from 171 * @param int $to 172 * @return int number of executed migrations 173 */ 174 protected function migrateUp($from, $to) 175 { 176 $con = Propel::getConnection(); 177 $counter = 0; 178 179 // iterate over all needed migrations 180 for ($i = $from + 1; $i <= $to; $i++) 181 { 182 if ($con instanceof PropelPDO) { 183 $con->beginTransaction(); 184 } else { 185 $con->begin(); 186 } 187 try 188 { 189 $migration = $this->getMigrationObject($i); 190 $migration->up(); 191 192 $this->setCurrentVersion($i); 193 194 $con->commit(); 195 } 196 catch (Exception $e) 197 { 198 $con->rollback(); 199 throw $e; 200 } 201 202 $counter++; 203 } 204 205 return $counter; 206 } 207 208 /** 209 * returns the migration object for the given version 210 * 211 * @param int $version 212 * @return sfMigration 213 */ 214 protected function getMigrationObject($version) 215 { 216 $file = $this->getMigrationFileName($version); 217 218 // load the migration class 219 require_once($file); 220 $migrationClass = 'Migration'.$this->getMigrationNumberFromFile($file); 221 222 return new $migrationClass($this, $version); 223 } 224 225 /** 226 * version to filename 227 * 228 * @param int $version 229 * @return string filename 230 */ 231 protected function getMigrationFileName($version) 232 { 233 return $this->migrations[$version-1]; 234 } 235 236 /** 237 * loads all migration file names 238 */ 239 protected function loadMigrations() 240 { 241 $this->migrations = sfFinder::type('file')->name('/^\d{3}.*\.php$/')->maxdepth(0)->in($this->getMigrationsDir()); 242 243 sort($this->migrations); 244 245 if (count($this->migrations) > 0) 246 { 247 $minVersion = $this->getMinVersion(); 248 $maxVersion = $this->getMaxVersion(); 249 250 if ($minVersion != 1) 251 { 252 throw new sfInitializationException("First migration is not migration 1. Some migration files may be missing."); 253 } 254 255 if (($maxVersion - $minVersion + 1) != count($this->migrations)) 256 { 257 throw new sfInitializationException("Migration count unexpected. Migration files may be missing. Migration numbers must be unique."); 258 } 259 } 260 } 261 262 /** 263 * returns the list of migration filenames 264 * 265 * @return array 266 */ 267 public function getMigrations() 268 { 269 return $this->migrations; 270 } 271 272 /** 273 * @return the lowest migration that exists 274 */ 275 public function getMinVersion() 276 { 277 if (count($this->migrations) == 0) 278 { 279 return 0; 280 } 281 else 282 { 283 return $this->getMigrationNumberFromFile($this->migrations[0]); 284 } 285 } 286 287 /** 288 * @return the highest existing migration number 289 */ 290 public function getMaxVersion() 291 { 292 if (count($this->migrations) == 0) 293 { 294 return 0; 295 } 296 else 297 { 298 return $this->getMigrationNumberFromFile($this->migrations[count($this->migrations)-1]); 299 } 300 } 301 302 /** 303 * retrives the current schema version from the database 304 * 305 * if no schema version is currently stored in the database, 306 * one is created and initialized with 0 307 * 308 * @return int 211 * @return integer 309 212 */ 310 213 public function getCurrentVersion() 311 214 { 312 215 // check if schema_info table exists 313 $result = self::executeQuery("SHOW TABLES LIKE 'schema_info'"); 314 315 $exists = false; 316 if ($result instanceof PDOStatement) { 317 $exists = ($result->rowCount() == 1); 318 } else { 319 $exists = ($result->getRecordCount() == 1); 320 } 321 322 if ($exists) 323 { 324 $result = self::executeQuery("SELECT version FROM schema_info"); 325 326 if ($result instanceof PDOStatement) 216 $result = $this->executeQuery('SHOW TABLES LIKE "schema_info"'); 217 218 if ($result instanceof PDOStatement ? $result->rowCount() : $result->getRecordCount()) 219 { 220 $result = $this->executeQuery('SELECT version FROM schema_info'); 221 222 if ($result instanceof PDOStatement) 327 223 { 328 224 $currentVersion = $result->fetchColumn(0); 329 } 330 else 225 } 226 else 331 227 { 332 228 if ($result->next()) … … 336 232 else 337 233 { 338 throw new sfDatabaseException( "unable to retrieve current schema version");234 throw new sfDatabaseException('Unable to retrieve current schema version.'); 339 235 } 340 236 } … … 342 238 else 343 239 { 344 // no schema_info table exists yet 345 // so we create it 346 self::executeUpdate("CREATE TABLE schema_info (version INTEGER UNSIGNED)"); 347 // and insert the version record 348 // if no schema_info existed before, we'll call that version 0 349 self::executeUpdate("INSERT INTO schema_info SET version = 0"); 240 // no schema_info table exists yet so we create it 241 $this->executeUpdate('CREATE TABLE schema_info (version INTEGER UNSIGNED)'); 242 243 // and insert the version record as 0 244 $this->executeUpdate('INSERT INTO schema_info SET version = 0'); 350 245 $currentVersion = 0; 351 246 } 352 247 353 248 return $currentVersion; 354 249 } 355 250 356 251 /** 357 * returns the number encoded in the given migration file name 358 * 359 * @param string $file the filename to look at 252 * Get the number encoded in the given migration file name. 253 * 254 * @param string $file The filename to look at 255 * 256 * @return integer 360 257 */ 361 258 public function getMigrationNumberFromFile($file) 362 259 { 363 $matches = array(); 364 $match_count = preg_match('#'.preg_quote(DIRECTORY_SEPARATOR, '#').'(\d{3}).*\.php$#', $file, $matches); 365 $number = $matches[1]; 366 367 if ($match_count < 1) { 368 throw new sfParseException("Migration filename could not be parsed."); 369 } 370 260 $number = substr(basename($file), 0, 3); 261 262 if (!ctype_digit($number)) 263 { 264 throw new sfParseException('Migration filename could not be parsed.'); 265 } 266 371 267 return $number; 372 268 } 269 270 /** 271 * Get the directory where migration classes are saved. 272 * 273 * @return string 274 */ 275 public function getMigrationsDir() 276 { 277 return sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'migrations'; 278 } 279 280 /** 281 * Get the directory where migration fixtures are saved. 282 * 283 * @return string 284 */ 285 public function getMigrationsFixturesDir() 286 { 287 return $this->getMigrationsDir().DIRECTORY_SEPARATOR.'fixtures'; 288 } 289 290 /** 291 * Write the given version as current version to the database. 292 * 293 * @param integer $version New current version 294 */ 295 protected function setCurrentVersion($version) 296 { 297 $version = (int) $version; 298 299 $this->executeUpdate("UPDATE schema_info SET version = $version"); 300 } 301 302 /** 303 * Migrate down, from version $from to version $to. 304 * 305 * @param integer $from 306 * @param integer $to 307 * 308 * @return integer Number of executed migrations 309 */ 310 protected function migrateDown($from, $to) 311 { 312 $con = Propel::getConnection(); 313 $counter = 0; 314 315 // iterate over all needed migrations 316 for ($i = $from; $i > $to; $i--) 317 { 318 try 319 { 320 $con instanceof PropelPDO ? $con->beginTransaction() : $con->begin(); 321 322 $migration = $this->getMigrationObject($i); 323 $migration->down(); 324 325 $this->setCurrentVersion($i-1); 326 327 $con->commit(); 328 } 329 catch (Exception $e) 330 { 331 $con->rollback(); 332 throw $e; 333 } 334 335 $counter++; 336 } 337 338 return $counter; 339 } 340 341 /** 342 * Migrate up, from version $from to version $to. 343 * 344 * @param integer $from 345 * @param integer $to 346 * @return integer Number of executed migrations 347 */ 348 protected function migrateUp($from, $to) 349 { 350 $con = Propel::getConnection(); 351 $counter = 0; 352 353 // iterate over all needed migrations 354 for ($i = $from + 1; $i <= $to; $i++) 355 { 356 try 357 { 358 $con instanceof PropelPDO ? $con->beginTransaction() : $con->begin(); 359 360 $migration = $this->getMigrationObject($i); 361 $migration->up(); 362 363 $this->setCurrentVersion($i); 364 365 $con->commit(); 366 } 367 catch (Exception $e) 368 { 369 $con->rollback(); 370 throw $e; 371 } 372 373 $counter++; 374 } 375 376 return $counter; 377 } 378 379 /** 380 * Get the migration object for the given version. 381 * 382 * @param integer $version 383 * 384 * @return sfMigration 385 */ 386 protected function getMigrationObject($version) 387 { 388 $file = $this->getMigrationFileName($version); 389 390 // load the migration class 391 require_once $file; 392 $migrationClass = 'Migration'.$this->getMigrationNumberFromFile($file); 393 394 return new $migrationClass($this, $version); 395 } 396 397 /** 398 * Version to filename. 399 * 400 * @param integer $version