<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,7 +1,24 @@
 ==== Migrate.php Changelog (started as of v3.0) ====
 
+TODO:
+ replace mdb2 with datadict
+ generate migrations in arrays format
+ transactions
+ web based interface?
+ FIXES:
+  options format - name: [string:32, notnull, 2]
+
+v 4.0 rc1 - May 2008 ...
+ [+] Version numbers now use timestamps so as to minimize conflicts
+ [+] Now supports interleaved migrations;
+        when migrating up, will run migrations that have not yet been run, and will ignore any non-run migrations when running down.
+ [+] Added info option (cake migrate info), which shows information on migrations
+ [+] Can now specify version number when running up/down, thus allowing you to only run the up/down block of a specific migration
+ [+] Schema table name is now customizable
+ [+] Now supports PHP arrays in migration files
+
 v 3.7 - Feb 28 2008
- [*] Removed backticks from table name when changing migration version, as they caused errors when using SQLITE.
+ [*] Removed back ticks from table name when changing migration version, as they caused errors when using SQLITE.
  [+] Now supports Cake's UUID columns
 
 v 3.6 - Jan 30 2008</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -39,4 +39,4 @@
 Please check out the examples directory within this package.
       
 Updates, new releases and other resources can be found at http://code.google.com/p/cakephp-migrations/
-For further assistance and additional resources, please check out my Blog at http://joelmoss.info
\ No newline at end of file
+For further assistance and additional resources, please check out my Blog at http://developingwithstyle.com
\ No newline at end of file</diff>
      <filename>INSTALL</filename>
    </modified>
    <modified>
      <diff>@@ -14,14 +14,32 @@ with everyone else's.
 The Migrations shell will generate a migration file for each DB change you want to make. This file
 can include any number of DB changes.
 
-The Migration files use YAML; the extremely simple and human friendly data standard. So instead of
-having to write SQL queries, you can write a short YAML structure that will do the same thing:
+The Migration files support YAML and PHP array's. So instead of having to write SQL queries, you
+can write a short YAML structure that will do the same thing:
 
   create_table:
     users:
       name: string
       age: int
       is_active: bool
+      
+or the equivalent in a PHP array:
+
+  array(
+    'create_table' =&gt; array(
+      'users' =&gt; array(
+        'name' =&gt; array(
+          'type' =&gt; 'string'
+        )
+        'age' =&gt; array(
+          'type' =&gt; 'int'
+        )
+        'is_active' =&gt; array(
+          'type' =&gt; 'bool'
+        )
+      )
+    )
+  )
 
 The above YAML code will create a table called 'users'. This is equivalent to running the following
 MySQL code:
@@ -45,4 +63,4 @@ into your database.
 Please check out the examples directory within this package.
 
 Updates, new releases and other resources can be found at http://code.google.com/p/cakephp-migrations/
-For further assistance and additional resources, please check out my Blog at http://joelmoss.info
\ No newline at end of file
+For further assistance and additional resources, please check out my Blog at http://developingwithstyle.com
\ No newline at end of file</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <diff>@@ -72,13 +72,15 @@ Before continuing, please be sure to read the README and INSTALL files included
   
     - Migrates down to 0 and back up o the latest version
 
-  cake migrate down
+  cake migrate down [version]
   
-    - Migrates down to the previous current version
+    - Migrates down to the previous current version.
+      If [version] is specified will run the DOWN section only on that specified version.
 
-  cake migrate up
+  cake migrate up [version]
   
-    - Migrates up from the current to the next version
+    - Migrates up from the current to the next version.
+      If [version] is specified will run the UP section only on that specified version.
 
   cake migrate help
   </diff>
      <filename>USAGE</filename>
    </modified>
    <modified>
      <diff>@@ -8,1347 +8,1370 @@
  * Licensed under The MIT License
  * Redistributions of files must retain the above copyright notice.
  *
- * @copyright		Copyright 2006-2008, Joel Moss
- * @link				http://joelmoss.info
- * @since			  CakePHP(tm) v 1.2
- * @license			http://www.opensource.org/licenses/mit-license.php The MIT License
+ * @copyright       Copyright 2006-2008, Joel Moss
+ * @link                http://developingwithstyle.com
+ * @since             CakePHP(tm) v 1.2
+ * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
  * 
 */
 
-uses('file', 'folder');
+App::import('Core', array('file', 'folder'));
 
 class MigrateShell extends Shell
 {
-  /**
-   * The datasource that should be used.
-   * You can modify this by passing
-   */
-  var $dataSource = 'default';
-  var $db;
-
-  var $types = array(
-	  'string',
-	  'text',
-	  'integer',
-	  'int',
-	  'blob',
-	  'boolean',
-	  'bool',
-	  'float',
-	  'date',
-	  'time',
-	  'timestamp',
-	  'fkey',
-	  'fkeys'
-	);
-	
-	var $uuid_format = array(
-	  'type'    =&gt; 'text',
-	  'notnull' =&gt; true,
-	  'length'  =&gt; 36
-	);
-	
-	var $id_format = array(
-	  'type'    =&gt; 'integer',
-	  'notnull' =&gt; true,
-	  'autoincrement'  =&gt; true
-	);
-	
-	var $use_uuid = false;
-
-  function startup()
-  {
-		define('MIGRATIONS_PATH', APP_PATH .'config' .DS. 'migrations');
+    /**
+    * The datasource that should be used.
+    */
+    var $dataSource = 'default';
+    
+    /**
+     * Name of the schema migrations table
+     */
+    var $schema_table = 'schema_migrations';
+    
+    /**
+     * The database object
+     */
+    var $db;
+    
+    /**
+     * Array of migrations
+     */
+    var $migrations = array();
     
-    if (isset($this-&gt;params['ds'])) $this-&gt;dataSource = $this-&gt;params['ds'];
-    if (isset($this-&gt;params['datasource'])) $this-&gt;dataSource = $this-&gt;params['datasource'];
+    /**
+     * Current migration data
+     */
+    var $current_migration = array(
+        'id' =&gt; 0,
+        'name' =&gt; '',
+        'filename' =&gt; '',
+        'format' =&gt; '',
+        'migrated' =&gt; false,
+        'migrated_on' =&gt; ''    
+    );
     
-    $this-&gt;_initDatabase();
+    /**
+     * Empty migration data
+     */
+    var $empty_migration = array(
+        'id' =&gt; 0,
+        'name' =&gt; '',
+        'filename' =&gt; '',
+        'format' =&gt; '',
+        'migrated' =&gt; false,
+        'migrated_on' =&gt; ''    
+    );
+
+    /**
+     * Target migration data
+     */
+    var $target_migration = array();
+    
+    /**
+     * Un-migrated migrations
+     */
+    var $unmigrated_migrations = array();
+    
+    /**
+     * If true, will use Cake's UUID's for primary key.
+     */
+    var $use_uuid = true;
+
+    /**
+     * DB column/field types
+     */
+    var $types = array(
+        'string',
+        'text',
+        'integer',
+        'int',
+        'blob',
+        'boolean',
+        'bool',
+        'float',
+        'date',
+        'time',
+        'timestamp',
+        'fkey',
+        'fkeys'
+    );
+    
+    var $uuid_format = array(
+        'type'    =&gt; 'text',
+        'notnull' =&gt; true,
+        'length'  =&gt; 36
+    );
+    
+    var $id_format = array(
+        'type'    =&gt; 'integer',
+        'notnull' =&gt; true,
+        'autoincrement'  =&gt; true
+    );
+
+    function startup()
+    {
+        define('MIGRATIONS_PATH', APP_PATH .'config' .DS. 'migrations');
     
-    $this-&gt;_welcome();
-		$this-&gt;out('App : '. APP_DIR);
-		$this-&gt;out('Path: '. ROOT . DS . APP_DIR);
-		$this-&gt;_getMigrationVersion();
-    $this-&gt;out('');
-		$this-&gt;out('Current schema version: '.$this-&gt;current_version);
-		$this-&gt;out('');
-		$this-&gt;_getMigrations();
-  }
+        if (isset($this-&gt;params['ds'])) $this-&gt;dataSource = $this-&gt;params['ds'];
+        if (isset($this-&gt;params['datasource'])) $this-&gt;dataSource = $this-&gt;params['datasource'];
+    
+        $this-&gt;_initDatabase();
+        $this-&gt;_getMigrations();
+    
+        $this-&gt;_welcome();
+        $this-&gt;out('App : '. APP_DIR);
+        $this-&gt;out('Path: '. ROOT . DS . APP_DIR);        
+        $this-&gt;out('');
+        $this-&gt;out('Current schema version:', false);
+        if ($this-&gt;current_migration['id'] == 0) {
+            $this-&gt;out('[none yet run]');
+        } else {
+            $this-&gt;out('#' . $this-&gt;current_migration['id'] . ' &quot;' . $this-&gt;current_migration['name'] . '&quot;');
+        }
+        $this-&gt;out('');
+    }
+  
+    /**
+     * Prints list of migration files and provides info about each one
+     */
+    function info()
+    {
+        $this-&gt;hr();
+        $this-&gt;out('');
+        $this-&gt;out('Your Migrations (' . count($this-&gt;migrations) . ') ...    (* denotes migration not yet run)');
+        $this-&gt;out('');
+        foreach ($this-&gt;migrations as $id =&gt; $migration) {
+            (!$migration['migrated']) ? $this-&gt;out('*', false) : $this-&gt;out(' ', false);
+            $this-&gt;out('[' . $id . '] ' . $migration['name'], false);
+            if ($migration['migrated_on']) {
+                $this-&gt;out('(migrated: ' . date(&quot;r&quot;, $migration['migrated_on']) . ')');
+            } else {
+                $this-&gt;out('');
+            }
+        }
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+    }
   
   /**
    * Main method: migrates to the latest version.
    */
-	function main()
-	{
-	  $this-&gt;to_version = (count($this-&gt;args) &amp;&amp; is_numeric($this-&gt;args[0])) ? $this-&gt;args[0] : $this-&gt;migration_count;
-    $this-&gt;_run();
-		$this-&gt;out('Migrations completed.');
-		$this-&gt;out('');
-		$this-&gt;hr();
-		$this-&gt;out('');
-    exit;
-	}
+    function main()
+    {
+        $to = (count($this-&gt;args) &amp;&amp; is_numeric($this-&gt;args[0])) ? $this-&gt;args[0] : $this-&gt;target_migration['id'];
+        $this-&gt;target_migration = $this-&gt;migrations[$to];
+        
+        $this-&gt;_run();
+        $this-&gt;out('Migrations completed.');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+        exit;
+    }
 
   /**
    * Migrates down to the previous version
    */
-	function down()
-	{
-    $this-&gt;to_version = ($this-&gt;current_version === 0) ? $this-&gt;current_version : $this-&gt;current_version - 1;
-    $this-&gt;_run();
-		$this-&gt;out('Migrations completed.');
-		$this-&gt;out('');
-		$this-&gt;hr();
-		$this-&gt;out('');
-    exit;
-	}
+    function down()
+    {
+        if (count($this-&gt;args) &amp;&amp; is_numeric($this-&gt;args[0])) {
+            $this-&gt;target_migration = $this-&gt;migrations[$this-&gt;args[0]];
+            $this-&gt;_run('down');
+        } else {
+            $this-&gt;target_migration = $this-&gt;empty_migration;
+            $this-&gt;_sortMigrations('down');
+            $use_next = false;
+            foreach ($this-&gt;migrations as $migration) {
+                if ($migration['id'] == $this-&gt;current_migration['id']) {
+                    $use_next = true;
+                    continue;
+                }
+                if ($use_next) {
+                    $this-&gt;target_migration = $migration;
+                    break;
+                }
+            }
+            $this-&gt;_run();
+        }
+
+        $this-&gt;out('Migrations completed.');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+        exit;
+    }
 
   /**
    * Migrates up to the next version
    */
-	function up()
-	{
-    $this-&gt;to_version = ($this-&gt;current_version == $this-&gt;migration_count) ? $this-&gt;current_version : $this-&gt;current_version + 1;
-    $this-&gt;_run();
-		$this-&gt;out('Migrations completed.');
-		$this-&gt;out('');
-		$this-&gt;hr();
-		$this-&gt;out('');
-    exit;
-	}
+    function up()
+    {
+        if (count($this-&gt;args) &amp;&amp; is_numeric($this-&gt;args[0])) {
+            $this-&gt;target_migration = $this-&gt;migrations[$this-&gt;args[0]];
+            $this-&gt;_run('up');
+        } else {
+            if ($this-&gt;target_migration['id'] != $this-&gt;current_migration['id']) {
+                $this-&gt;target_migration = $this-&gt;empty_migration;
+                $use_next = false;
+                foreach ($this-&gt;migrations as $migration) {
+                    if ($this-&gt;current_migration['id'] === 0 || $use_next) {
+                        $this-&gt;target_migration = $migration;
+                        break;
+                    }
+                    if ($migration['id'] == $this-&gt;current_migration['id']) {
+                        $use_next = true;
+                        continue;
+                    }
+                }
+            }
+            $this-&gt;_run();
+        }
+
+        $this-&gt;out('Migrations completed.');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+        exit;
+    }
+
+    /**
+     * Reset's migration version without running migrations up or down and drops all tables
+     */
+    function reset()
+    {
+        $this-&gt;hr();
+        $this-&gt;out('');
+        $this-&gt;out('Resetting Migrations...');
+        $this-&gt;out('');
+
+        $tables = $this-&gt;_db-&gt;listTables();
+        foreach ($tables as $table) {
+            if ($table == $this-&gt;schema_table) continue;
+            $r = $this-&gt;_db-&gt;dropTable($table);
+            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+            $this-&gt;out('  Table \''.$table.'\' has been dropped.');
+        }
+
+        $r = $this-&gt;_db-&gt;exec(&quot;DELETE FROM {$this-&gt;schema_table}&quot;);
+        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+        
+        $this-&gt;out('');
+        $this-&gt;out('  Current migration version reset.');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+        exit;
+    }
+
+    /**
+     * Runs all migrations from the current version down and back up to the latest version.
+     */
+    function all()
+    {
+        if ($this-&gt;current_migration['id'] === 0) {
+            $this-&gt;_run();
+        } else {
+            $_target = $this-&gt;target_migration;
+            $this-&gt;target_migration = $this-&gt;empty_migration;
+            $this-&gt;_run();
+            $this-&gt;current_migration = $this-&gt;empty_migration;
+            $this-&gt;target_migration = $_target;
+            $this-&gt;_run();
+        }
+
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+        $this-&gt;out('All migrations completed.');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+        exit;
+    }
 
   /**
    * Migrates the full_schema.yml migration file.
    */
-	function full_schema()
-	{
-		if ($this-&gt;current_version &gt; 0)
-		{
-      $this-&gt;to_version = 0;
-      $this-&gt;_run();
+    function full_schema()
+    {
+        if ($this-&gt;current_version &gt; 0) {
+            $this-&gt;to_version = 0;
+            $this-&gt;_run();
+        }
+        $res = $this-&gt;_startMigration(MIGRATIONS_PATH .DS. 'full_schema.yml', 'up');
+        exit;
+    }
+
+    function _fromDb()
+    {
+        $this-&gt;_getTables();
+        if (empty($this-&gt;__tables)) $this-&gt;error('', '  There are currently no tables found in the database.');
+
+        if (count($this-&gt;args) == 2) {
+            $this-&gt;out('');
+            $this-&gt;hr();
+            $this-&gt;out('Creating full schema migration for all tables in database...');
+            $this-&gt;hr();
+            $this-&gt;_buildSchema($this-&gt;__tables, true);
+        } else {
+            unset($this-&gt;args[0], $this-&gt;args[1]);
+
+            // check if provided tables are in DB
+            foreach ($this-&gt;args as $val) {
+                if (!in_array($val , $this-&gt;__tables)) $this-&gt;err(&quot;Table '$val' not in database!&quot;);
+            }
+            $this-&gt;hr();
+            $this-&gt;out('Creating migrations for given tables in database...');
+            $this-&gt;hr();
+            $this-&gt;_buildSchema($this-&gt;args);
+        }
+        $this-&gt;out('');
     }
-		$res = $this-&gt;_startMigration(MIGRATIONS_PATH .DS. 'full_schema.yml', 'up');
-    exit;
-	}
-
-  function _fromDb()
-  {
-    $this-&gt;_getTables();
-    if (empty($this-&gt;__tables)) $this-&gt;error('', '  There are currently no tables found in the database.');
-    
-	  if (count($this-&gt;args) == 2)
-	  {
-		  $this-&gt;out('');
-	    $this-&gt;hr();
-  		$this-&gt;out('Creating full schema migration for all tables in database...');
-  		$this-&gt;hr();
-  		$this-&gt;_buildSchema($this-&gt;__tables, true);
-	  }
-	  else
-	  {
-  		unset($this-&gt;args[0], $this-&gt;args[1]);
-
-	    // check if provided tables are in DB
-	    foreach ($this-&gt;args as $val)
-	    {
-	      if (!in_array($val , $this-&gt;__tables)) $this-&gt;err(&quot;Table '$val' not in database!&quot;);
-	    }
-	    $this-&gt;hr();
-  		$this-&gt;out('Creating migrations for given tables in database...');
-  		$this-&gt;hr();
-  		$this-&gt;_buildSchema($this-&gt;args);
-	  }
-	  $this-&gt;out('');
-  }
   
-	/**
-	 * Burns the provided tables Schema into a YAML file suitable for migrations
-	 *
-	 * @param array $tables
-	 * @return unknown
-	 */
-	function _buildSchema($tables = null, $allTables = false)
-	{
-		if (!is_array($tables)) $tables = array($tables);
-		
-		$__tables = $this-&gt;_filterMigrationTable($tables);
-
-		if (empty($__tables)) $this-&gt;error('', '  There are currently no tables found in the database.');
-
-		if (!$allTables)
-		{
-		  $this-&gt;_getMigrations();
-		  
-		  $i=0;
-		  foreach ($__tables as $__table)
-		  {
-		    $out = $this-&gt;_buildYaml($__table);
-    		$new_migration_count = $this-&gt;_versionIt($this-&gt;migration_count+$i++);
-    		$this-&gt;createFile(MIGRATIONS_PATH .DS. $new_migration_count .'_create_'. $__table. '.yml', $out);
-		  }
-		}
-		else
-		{
-    	$this-&gt;createFile(MIGRATIONS_PATH .DS. 'full_schema.yml', $this-&gt;_buildYaml($__tables));
-		}
-	}
-	
-  function _buildYaml($tables)
-  {
-    if (!is_array($tables)) $tables = array($tables);
-
-    foreach ($tables as $table)
+    /**
+     * Burns the provided tables Schema into a YAML file suitable for migrations
+     *
+     * @param array $tables
+     * @return unknown
+     */
+    function _buildSchema($tables = null, $allTables = false)
     {
-  		$dbShema['UP']['create_table'][$table] = $this-&gt;__buildUpSchema($table);
-  		$dbShema['DOWN']['drop_table'][] = $table;
-	  }
-	  
-	  if (count($dbShema['DOWN']['drop_table']) == 1) $dbShema['DOWN']['drop_table'] = $dbShema['DOWN']['drop_table'][0];
-
-		// print file header
-		$out  = '#'.&quot;\n&quot;;
-		$out .= '# migration YAML file'.&quot;\n&quot;;
-		$out .= '#'.&quot;\n&quot;;
-		
-		if (function_exists('syck_dump'))
-		{
-			return @syck_dump($dbShema);
-		}
-		else
-		{
-			vendor('Spyc');
-			return Spyc::YAMLDump($dbShema);
-		}
-  }
-	
-	function __buildUpSchema($tableName)
-	{
-    $useTable = low(Inflector::pluralize($tableName));
+        if (!is_array($tables)) $tables = array($tables);
+        
+        $__tables = $this-&gt;_filterMigrationTable($tables);
+
+        if (empty($__tables)) $this-&gt;error('', '  There are currently no tables found in the database.');
+
+        if (!$allTables) {
+            $this-&gt;_getMigrations();
+
+            $i=0;
+            foreach ($__tables as $__table) {
+                $out = $this-&gt;_buildYaml($__table);
+                $new_migration_count = $this-&gt;_versionIt($this-&gt;migration_count+$i++);
+                $this-&gt;createFile(MIGRATIONS_PATH .DS. $new_migration_count .'_create_'. $__table. '.yml', $out);
+            }
+        } else {
+            $this-&gt;createFile(MIGRATIONS_PATH .DS. 'full_schema.yml', $this-&gt;_buildYaml($__tables));
+        }
+    }
     
-    App::import('Model');       
-    $tempModel = new Model(false, $tableName);
+    function _buildYaml($tables)
+    {
+        if (!is_array($tables)) $tables = array($tables);
+
+        foreach ($tables as $table) {
+            $dbShema['UP']['create_table'][$table] = $this-&gt;__buildUpSchema($table);
+            $dbShema['DOWN']['drop_table'][] = $table;
+        }
+
+        if (count($dbShema['DOWN']['drop_table']) == 1) $dbShema['DOWN']['drop_table'] = $dbShema['DOWN']['drop_table'][0];
+
+        // print file header
+        $out  = '#'.&quot;\n&quot;;
+        $out .= '# migration YAML file'.&quot;\n&quot;;
+        $out .= '#'.&quot;\n&quot;;
+        
+        if (function_exists('syck_dump')) {
+            return @syck_dump($dbShema);
+        } else {
+            vendor('Spyc');
+            return Spyc::YAMLDump($dbShema);
+        }
+    }
     
-		$db =&amp; ConnectionManager::getDataSource($this-&gt;dataSource);
-		$modelFields = $db-&gt;describe($tempModel);
-		
-		if (!array_key_exists('created', $modelFields) &amp;&amp; !array_key_exists('modified', $modelFields))
-		{
-		  $tableSchema['no_dates'] = '';
-	  }
-	  elseif (!array_key_exists('created', $modelFields) || !array_key_exists('modified', $modelFields))
-		{
-		  $tableSchema[] = array_key_exists('created', $modelFields) ? 'modified' : 'created';
-		  $tableSchema['no_dates'] = '';
-	  }
-		
-		foreach ($modelFields as $key=&gt;$item)
-		{
-	    if ($key != 'id' AND $key != 'created' AND $key != 'modified')
-	    {
-        $tableSchema[$key]['type'] = $item['type'];
-        if (!empty($item['default'])) $tableSchema[$key]['default'] = $item['default'];
-        $tableSchema[$key]['length'] = $item['length'];                          
-        if ($item['null'])
-        {
-          $tableSchema[$key]['is_null'] = '';
+    function __buildUpSchema($tableName)
+    {
+        $useTable = low(Inflector::pluralize($tableName));
+    
+        App::import('Model');       
+        $tempModel = new Model(false, $tableName);
+        
+        $db =&amp; ConnectionManager::getDataSource($this-&gt;dataSource);
+        $modelFields = $db-&gt;describe($tempModel);
+        
+        if (!array_key_exists('created', $modelFields) &amp;&amp; !array_key_exists('modified', $modelFields)) {
+            $tableSchema['no_dates'] = '';
+        } elseif (!array_key_exists('created', $modelFields) || !array_key_exists('modified', $modelFields)) {
+            $tableSchema[] = array_key_exists('created', $modelFields) ? 'modified' : 'created';
+            $tableSchema['no_dates'] = '';
         }
-        else
-        {
-          $tableSchema[$key]['not_null'] = '';
+        
+        foreach ($modelFields as $key=&gt;$item) {
+            if ($key != 'id' AND $key != 'created' AND $key != 'modified') {
+                $tableSchema[$key]['type'] = $item['type'];
+                if (!empty($item['default'])) $tableSchema[$key]['default'] = $item['default'];
+                $tableSchema[$key]['length'] = $item['length'];                          
+                if ($item['null']) {
+                    $tableSchema[$key]['is_null'] = '';
+                } else {
+                    $tableSchema[$key]['not_null'] = '';
+                }
+            }
         }
-	    }
-		}
-		
-		if (!array_key_exists('id', $modelFields)) $tableSchema[] = 'no_id';
-		return $tableSchema; 
-	}
-
-	/**
+        
+        if (!array_key_exists('id', $modelFields)) $tableSchema[] = 'no_id';
+        return $tableSchema; 
+    }
+
+    /**
    * Forces the user to specify the model he wants to bake, and returns the selected model name.
    *
    * @return the model name
    */
-	function _getName()
-	{
-		$this-&gt;_listAll($this-&gt;dataSource);
-
-		$enteredModel = '';
-
-		while ($enteredModel == '')
-		{
-			$enteredModel = $this-&gt;in('Enter a number from the list above, or type in the name of another model.');
-			if ($enteredModel == '' || intval($enteredModel) &gt; count($this-&gt;_modelNames))
-			{
-				$this-&gt;out('Error:');
-				$this-&gt;out(&quot;The model name you supplied was empty, or the number&quot;);
-				$this-&gt;out(&quot;you selected was not an option. Please try again.&quot;);
-				$enteredModel = '';
-			}
-		}
-
-		if (intval($enteredModel) &gt; 0 &amp;&amp; intval($enteredModel) &lt;= count($this-&gt;_modelNames))
-		{
-			return $this-&gt;_modelNames[intval($enteredModel) - 1];
-		}
-		else
-		{
-			return $enteredModel;
-		}
-	}
-	
-	/**
+    function _getName()
+    {
+        $this-&gt;_listAll($this-&gt;dataSource);
+
+        $enteredModel = '';
+
+        while ($enteredModel == '') {
+            $enteredModel = $this-&gt;in('Enter a number from the list above, or type in the name of another model.');
+            if ($enteredModel == '' || intval($enteredModel) &gt; count($this-&gt;_modelNames)) {
+                $this-&gt;out('Error:');
+                $this-&gt;out(&quot;The model name you supplied was empty, or the number&quot;);
+                $this-&gt;out(&quot;you selected was not an option. Please try again.&quot;);
+                $enteredModel = '';
+            }
+        }
+
+        if (intval($enteredModel) &gt; 0 &amp;&amp; intval($enteredModel) &lt;= count($this-&gt;_modelNames)) {
+            return $this-&gt;_modelNames[intval($enteredModel) - 1];
+        } else {
+            return $enteredModel;
+        }
+    }
+    
+    /**
     * Outputs the a list of possible models or controllers from database
     *
     * @return output
     */
-	function _listAll()
-	{
-		$this-&gt;_getTables();
-		$this-&gt;out('');
-		$this-&gt;out('Possible Models based on your current database:');
-		$this-&gt;hr();
-		$this-&gt;_modelNames = array();
-		$i=1;
-		foreach ($this-&gt;__tables as $table)
-		{
-			$this-&gt;_modelNames[] = $this-&gt;_modelName($table);
-			$this-&gt;out($i++ . &quot;. &quot; . $this-&gt;_modelName($table));
-		}
-	}
-	
-	/**
-	 * Gets the tables in DB according to your connection configuration
-	 */
-	function _getTables()
-	{
-	  $db =&amp; ConnectionManager::getDataSource($this-&gt;dataSource);
-		$usePrefix = empty($db-&gt;config['prefix']) ? '' : $db-&gt;config['prefix'];
-		if ($usePrefix)
-		{
-			$tables = array();
-			foreach ($db-&gt;listSources() as $table)
-			{
-				if (!strncmp($table, $usePrefix, strlen($usePrefix)))
-				{
-					$tables[] = substr($table, strlen($usePrefix));
-				}
-			}
-		}
-		else
-		{
-			$tables = $db-&gt;listSources();
-		}
-		$this-&gt;__tables = $this-&gt;_filterMigrationTable($tables);
-	}
-	
-  function _filterMigrationTable($myTables)
-  {
-    $filteredArray = Set::remove($myTables, array_search('schema_info', $myTables));
-    sort($filteredArray);
-  	return $filteredArray;
-  }
-
-  /**
-   * Generates a migration file. You can pass the file name on the command line, or wait for the prompt.
-   * 
-   * Example: 'cake migrate generate my migration file name'
-   */
-	function generate()
-	{
-		if (count($this-&gt;args))
-		{
-		  if ($this-&gt;args[0] == 'from' &amp;&amp; $this-&gt;args[1] == 'db')
-		  {
-		    $this-&gt;_fromDb();
-		    exit;
-		  }
-		  else
-		  {
-		    if (count($this-&gt;args) == 2 &amp;&amp; $this-&gt;args[0] == 'create') $table_name = $this-&gt;args[1];
-		    $name = low(implode(&quot;_&quot;, $this-&gt;args));
-	    }
-		}
-		
-		$this-&gt;hr();
-		if (empty($name))
-		{
-      $invalidSelection = true;
-		  while ($invalidSelection)
-		  {
-		    $name = $this-&gt;in('  Please enter the descriptive name of the migration to generate:');
-    		if (!preg_match(&quot;/^([a-z0-9]+|\s)+$/&quot;, $name))
-    		{
-    			$this-&gt;err('Migration name ('.$name.') is invalid. It must only contain alphanumeric characters.');
-    		}
-    		else
-    		{
-    		  $name = str_replace(&quot; &quot;, &quot;_&quot;, $name);
-    		  if ($name == 'session' || $name == 'sessions') $name = 'create_sessions';
-    		  $invalidSelection = false;
-    		}
-			}
-  	}
-  	
-    $folder = new Folder(MIGRATIONS_PATH, true, '777');
-    $files = $folder-&gt;find(&quot;[0-9]+_$name.yml&quot;);
-    if (count($files))
+    function _listAll()
     {
-      if (strtoupper($this-&gt;in(&quot;A migration file of the same name already exists ({$files[0]}). Continue anyway?&quot;, array('Y', 'N'), 'N')) == 'N') exit;
+        $this-&gt;_getTables();
+        $this-&gt;out('');
+        $this-&gt;out('Possible Models based on your current database:');
+        $this-&gt;hr();
+        $this-&gt;_modelNames = array();
+        $i=1;
+        foreach ($this-&gt;__tables as $table) {
+            $this-&gt;_modelNames[] = $this-&gt;_modelName($table);
+            $this-&gt;out($i++ . &quot;. &quot; . $this-&gt;_modelName($table));
+        }
     }
     
-		$this-&gt;_getMigrations();
-		$new_migration_count = $this-&gt;_versionIt($this-&gt;migration_count+1);
-		$filename = MIGRATIONS_PATH . DS .$new_migration_count . '_' . $name . '.yml';
-		if ($name == 'create_sessions')
-		{
-      $data = &quot;#\n# migration YAML file\n#\nUP:\n  create_table:\n    sessions:\n      id: [string, 32, primary]\n      data: text\n      expires: integer\n      - no_dates\nDOWN:\n  drop_table: sessions&quot;;
-		}
-		else
-		{
-		  if (isset($table_name))
-		  {
-        $data = &quot;#\n# migration YAML file\n#\nUP:\n  create_table:\n    $table_name:\n      column:\nDOWN:\n  drop_table: $table_name&quot;;
-		  }
-		  else
-		  {
-		    $data = &quot;#\n# migration YAML file\n#\nUP:\n  create_table:\n    table_name:\n      name:\n      description: text\n      count: integer\n      is_active: boolean\nDOWN:\n  drop_table: table_name&quot;;
-		  }
-	  }
-		$file = new File($filename, true, 0777);
-		$file-&gt;write($data);
-
-		$this-&gt;out('');
-		$this-&gt;out('Generation of migration file: \''.$name.'\' completed.');
-		$this-&gt;out('Please edit \'' . $filename . '\' to customise your migration.');
-		$this-&gt;out('');
-		$this-&gt;hr();
-		
-		$this-&gt;_mate($filename);
-		exit;
-	}
-	
-	/**
-	 * Aliases for generate method
-	 */
-	function gen() { $this-&gt;generate(); }
-	function g() { $this-&gt;generate(); }
-
-  /**
-   * Reset migration version to zero without running migrations up or down and drops all tables
-   */
-	function reset()
-	{
-    $this-&gt;hr();
-    $this-&gt;out('');
-		$this-&gt;out('Resetting Migrations...');
-
-		$tables = $this-&gt;_db-&gt;listTables();
-		foreach ($tables as $table)
-		{
-			if ($table == 'schema_info') continue;
-			$r = $this-&gt;_db-&gt;dropTable($table);
-			if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-			$this-&gt;out('');
-			$this-&gt;out('  Table \''.$table.'\' has been dropped.');
-		}
-
-		$r = $this-&gt;_db-&gt;exec(&quot;UPDATE `schema_info` SET version=0&quot;);
-		if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-		$this-&gt;out('');
-		$this-&gt;out('Current migrations version reset to zero and all tables dropped.');
-		$this-&gt;out('');
-		$this-&gt;hr();
-		$this-&gt;out('');
-		exit;
-	}
-
-  /**
-   * Runs all migrations from the current version down and back up to the latest version.
-   */
-  function all()
-  {
-		if ($this-&gt;current_version &gt; 0)
-		{
-      $this-&gt;to_version = 0;
-      $this-&gt;_run();
+    /**
+     * Gets the tables in DB according to your connection configuration
+     */
+    function _getTables()
+    {
+        $db =&amp; ConnectionManager::getDataSource($this-&gt;dataSource);
+        $usePrefix = empty($db-&gt;config['prefix']) ? '' : $db-&gt;config['prefix'];
+        if ($usePrefix) {
+            $tables = array();
+            foreach ($db-&gt;listSources() as $table) {
+                if (!strncmp($table, $usePrefix, strlen($usePrefix))) {
+                    $tables[] = substr($table, strlen($usePrefix));
+                }
+            }
+        } else {
+            $tables = $db-&gt;listSources();
+        }
+        $this-&gt;__tables = $this-&gt;_filterMigrationTable($tables);
     }
-    $this-&gt;to_version = $this-&gt;migration_count;
-    $this-&gt;_getMigrationVersion();
-    $this-&gt;_run();
     
-		$this-&gt;out('');
-		$this-&gt;hr();
-		$this-&gt;out('');
-		$this-&gt;out('All migrations completed.');
-		$this-&gt;out('');
-		$this-&gt;hr();
-		$this-&gt;out('');
-    exit;
-  }
-
-	function _run()
-	{
-		$this-&gt;hr();
-		if ($this-&gt;migration_count === 0)
-		{
-			$this-&gt;out('');
-			$this-&gt;out('  ** No migrations found **');
-			$this-&gt;out('');
-			$this-&gt;hr();
-			$this-&gt;out('');
-			exit;
-		}
-
-		$new_version = $this-&gt;to_version;
-
-		if (!is_numeric($new_version))
-		{
-			$this-&gt;out('');
-			$this-&gt;out('  ** Migration version number ('.$new_version.') is invalid. **');
-			$this-&gt;out('');
-			$this-&gt;hr();
-			$this-&gt;out('');
-			exit;
-		}
-		if ($new_version &gt; $this-&gt;migration_count)
-		{
-			$this-&gt;out('');
-			$this-&gt;out('  ** Version number entered ('.$new_version.') does not exist. **');
-			$this-&gt;out('');
-			$this-&gt;hr();
-			$this-&gt;out('');
-			exit;
-		}
-		if ($this-&gt;current_version == $new_version)
-		{
-			$this-&gt;out('');
-			$this-&gt;out('  ** Migrations are up to date **');
-			$this-&gt;out('');
-			$this-&gt;hr();
-			$this-&gt;out('');
-			exit;
-		}
-
-		$direction = ($new_version &lt; $this-&gt;current_version) ? 'down' : 'up';
-		if ($direction == 'down') usort($this-&gt;migrations, array($this, '_downMigrations'));
-		elseif ($direction == 'up') usort($this-&gt;migrations, array($this, '_upMigrations'));
-
-		$this-&gt;out('');
-		$this-&gt;out(&quot;Migrating database $direction from version {$this-&gt;current_version} to $new_version ...&quot;);
-		$this-&gt;out('');
-
-		foreach($this-&gt;migrations as $migration_name)
-		{
-			preg_match(&quot;/^([0-9]+)\_(.+)(\.yml)$/&quot;, $migration_name, $match);
-			$num = $this-&gt;_versionIt($match[1]);
-			$name = Inflector::humanize($match[2]);
-
-			if ($direction == 'up')
-			{
-				if ($num &lt;= $this-&gt;current_version) continue;
-				if ($num &gt; $new_version) break;
-			}
-			else
-			{
-				if ($num &gt; $this-&gt;current_version) continue;
-				if ($num == $new_version) break;
-			}
-
-			$this-&gt;out(&quot;  [$num] $name ...&quot;);
-
-			$this-&gt;running_migration_name = $migration_name;
-
-			$res = $this-&gt;_startMigration(MIGRATIONS_PATH .DS. $migration_name, $direction);
-			if ($res == 1)
-			{
-				$this-&gt;out('');
-				if ($direction == 'up')
-				{
-					$r = $this-&gt;_db-&gt;exec(&quot;UPDATE schema_info SET version=version+1&quot;);
-					if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-				}
-				else
-				{
-					$r = $this-&gt;_db-&gt;exec(&quot;UPDATE schema_info SET version=version-1&quot;);
-					if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-				}
-			}
-			else
-			{
-				$this-&gt;out(&quot;  ERROR: $res&quot;);
-				$this-&gt;hr();
-				return;
-			}
-		}
-	}
-
-	function _startMigration($file, $direction)
-	{
-		$yml = $this-&gt;_parsePhp($file);
-
-		if (function_exists('syck_load'))
-		{
-			$array = @syck_load($yml);
-		}
-		else
-		{
-			vendor('Spyc');
-			$array = Spyc::YAMLLoad($yml);
-		}
-
-		if (!is_array($array)) return &quot;Unable to parse YAML Migration file&quot;;
-		if (!$array[strtoupper($direction)]) return &quot;Direction does not exist!&quot;;
-		return $this-&gt;_array2Sql($array[strtoupper($direction)]);
-	}
-
-  /**
-   * Function description
-   * @param
-   * @return
-   */
-  function _getProperties($props)
-  {
-    $_props = array();
-    if (!is_array($props)) $props = array($props);
+    function _filterMigrationTable($myTables)
+    {
+        $filteredArray = Set::remove($myTables, array_search($this-&gt;schema_table, $myTables));
+        sort($filteredArray);
+        return $filteredArray;
+    }
 
-    foreach ($props as $prop)
+    /**
+     * Generates a migration file. You can pass the file name on the command line, or wait for the prompt.
+     * 
+     * Example: 'cake migrate generate my migration file name'
+     */
+    function generate()
     {
-  	  switch ($prop)
-  	  {
-  	    case is_numeric($prop):
-  	      $_props['length'] = $prop;
-  	      break;
-  	    case 'is_null':
-  	    case 'isnull':
-  	      $_props['notnull'] = false;
-  	      break;
-  	    case 'not_null':
-  	    case 'notnull':
-  	      $_props['notnull'] = true;
-  	      break;
-  	    case in_array($prop, $this-&gt;types):
-  	      $_props['type'] = $prop;
-  	      break;
-  	    case 'index':
-  	      $_props['index'] = true;
-  	      break;
-  	    case 'unique':
-  	      $_props['unique'] = true;
-  	      break;
-  	    case 'primary':
-  	      $_props['primary'] = true;
-  	      break;
-  	    case 'no_dates':
-  	      $_props['no_dates'] = true;
-  	      break;
-  	    case 'no_id':
-  	      $_props['no_id'] = true;
-  	      break;
-  	    default:
-  	      $_props['default'] = $prop;
-  	      break;
-  	  }
+        if (count($this-&gt;args)) {
+            if ($this-&gt;args[0] == 'from' &amp;&amp; $this-&gt;args[1] == 'db') {
+                $this-&gt;_fromDb();
+                exit;
+            } else {
+                if (count($this-&gt;args) == 2 &amp;&amp; $this-&gt;args[0] == 'create') $table_name = $this-&gt;args[1];
+                $name = low(implode(&quot;_&quot;, $this-&gt;args));
+            }
+        }
+        
+        $this-&gt;hr();
+        if (empty($name)) {
+            $invalidSelection = true;
+            while ($invalidSelection) {
+                $name = $this-&gt;in('  Please enter the descriptive name of the migration to generate:');
+                if (!preg_match(&quot;/^([a-z0-9]+|\s)+$/&quot;, $name)) {
+                    $this-&gt;err('Migration name ('.$name.') is invalid. It must only contain alphanumeric characters.');
+                } else {
+                    $name = str_replace(&quot; &quot;, &quot;_&quot;, $name);
+                    if ($name == 'session' || $name == 'sessions') $name = 'create_sessions';
+                    $invalidSelection = false;
+                }
+            }
+        }
+    
+        $folder = new Folder(MIGRATIONS_PATH, true, '777');
+        $files = $folder-&gt;find(&quot;[0-9]+_$name.yml&quot;);
+        if (count($files)) {
+            if (strtoupper($this-&gt;in(&quot;A migration file of the same name already exists ({$files[0]}). Continue anyway?&quot;, array('Y', 'N'), 'N')) == 'N') exit;
+        }
+    
+        $filename = MIGRATIONS_PATH . DS . gmdate(&quot;U&quot;) . '_' . $name . '.yml';
+        if ($name == 'create_sessions') {
+            $data = &quot;#\n# migration YAML file\n#\nUP:\n  create_table:\n    sessions:\n      id: [string, 32, primary]\n      data: text\n      expires: integer\n      - no_dates\nDOWN:\n  drop_table: sessions&quot;;
+        } else {
+            if (isset($table_name)) {
+                $data = &quot;#\n# migration YAML file\n#\nUP:\n  create_table:\n    $table_name:\n      column:\nDOWN:\n  drop_table: $table_name&quot;;
+            } else {
+                $data = &quot;#\n# migration YAML file\n#\nUP:\n  create_table:\n    table_name:\n      name:\n      description: text\n      count: integer\n      is_active: boolean\nDOWN:\n  drop_table: table_name&quot;;
+            }
+        }
+        $file = new File($filename, true, 0777);
+        $file-&gt;write($data);
+
+        $this-&gt;out('');
+        $this-&gt;out('Generation of migration file: \''.$name.'\' completed.');
+        $this-&gt;out('Please edit \'' . $filename . '\' to customise your migration.');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        
+        $this-&gt;_mate($filename);
+        exit;
     }
-    if (!array_key_exists('type', $_props)) $_props['type'] = 'string';
-	  return $_props;
-  }
-
-	function _array2Sql($array)
-	{
-	  foreach ($array as $name=&gt;$action)
-		{
-			if ($name == 'create_table' || $name == 'create_tables')
-			{
-				foreach ($action as $table=&gt;$fields)
-				{
-				  $this-&gt;out(&quot;      &gt; creating table '$table'&quot;);
-
-					$rfields = array();
-					$table_props = array();
-					$indexes = array();
-					$uniques = array();
-					$pk = array();
-					
-          if (isset($fields[0])) $fields = am($fields, $this-&gt;_getProperties($fields[0]));
-          unset($fields[0]);
-
-					if (!isset($fields['no_id']))
-					{
-					  $rfields['id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-					}
-					
-					foreach ($fields as $field=&gt;$props)
-					{
-						if (preg_match(&quot;/^no_id|created|modified|no_dates|fkey|fkeys$/&quot;, $field)) continue;
-						
-						if (!empty($props)) $props = $this-&gt;_getProperties($props);
-
-						if (preg_match(&quot;/\\_id$/&quot;, $field) &amp;&amp; count($props) &lt; 1)
-						{
-						  $rfields[$field] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-						  $indexes[] = $field;
-						  continue;
-						}
-
-            if ($props['type'] == 'int')
-            {
-              $props['type'] = 'integer';
-              $rfields[$field]['type'] = 'integer';
+    
+    /**
+     * Aliases for generate method
+     */
+    function gen() { $this-&gt;generate(); }
+    function g() { $this-&gt;generate(); }
+
+    function _run($target_direction = null)
+    {
+        $this-&gt;hr();
+        if (count($this-&gt;migrations) === 0) {
+            $this-&gt;out('');
+            $this-&gt;out('  ** No migrations found **');
+            $this-&gt;out('');
+            $this-&gt;hr();
+            $this-&gt;out('');
+            exit;
+        }
+
+        if (!is_null($target_direction)) {
+
+            if ($target_direction == 'up' &amp;&amp; $this-&gt;target_migration['migrated'] || $target_direction == 'down' &amp;&amp; !$this-&gt;target_migration['migrated']) {
+                $this-&gt;out('');
+                $this-&gt;out('  ** Migrations are up to date **');
+                $this-&gt;out('');
+                $this-&gt;hr();
+                $this-&gt;out('');
+                exit;
             }
-            
-            if ($props['type'] == 'bool')
-            {
-              $props['type'] = 'boolean';
-              $rfields[$field]['type'] = 'boolean';
+
+            $this-&gt;out('');
+            $this-&gt;out(&quot;Running $target_direction section of #{$this-&gt;target_migration['id']} ...&quot;);
+            $this-&gt;out('');
+            $this-&gt;out(&quot;  [{$this-&gt;target_migration['id']}] {$this-&gt;target_migration['name']} ...&quot;);
+
+            $res = $this-&gt;_startMigration($this-&gt;target_migration['id'], $target_direction);
+            if ($res == 1) {
+                $this-&gt;out('');
+                $time = gmdate(&quot;U&quot;);
+                if ($target_direction == 'up') {
+                    $r = $this-&gt;_db-&gt;exec(&quot;INSERT INTO {$this-&gt;schema_table} SET version = {$this-&gt;target_migration['id']}, datetime = $time&quot;);
+                    if (PEAR::isError($r)) {
+                        $this-&gt;err($r-&gt;getDebugInfo());
+                    } else {
+                        $this-&gt;migrations[$this-&gt;target_migration['id']]['migrated'] = true;
+                        $this-&gt;migrations[$this-&gt;target_migration['id']]['migrated_on'] = $time;
+                    }
+                } else {
+                    $r = $this-&gt;_db-&gt;exec(&quot;DELETE FROM {$this-&gt;schema_table} WHERE version = {$this-&gt;target_migration['id']}&quot;);
+                    if (PEAR::isError($r)) {
+                        $this-&gt;err($r-&gt;getDebugInfo());
+                    } else {
+                        $this-&gt;migrations[$this-&gt;target_migration['id']]['migrated'] = false;
+                        $this-&gt;migrations[$this-&gt;target_migration['id']]['migrated_on'] = '';
+                    }
+                }
+                return;
+            } else {
+                $this-&gt;out(&quot;  ERROR: $res&quot;);
+                $this-&gt;hr();
+                return;
             }
+        }
 
-						if ($props['type'] == 'fkey')
-						{
-						  $rfields[$field.'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-						  $indexes[] = $field.'_id';
-						  continue;
-					  }
-
-            $props['type'] = isset($props['type']) ? $props['type'] : 'string';
-						$rfields[$field]['type'] = $props['type'];
-						if ($props['type'] == 'string')
-						{
-						  $rfields[$field]['type'] = 'text';
-						  if (!isset($props['length'])) $rfields[$field]['length'] = 255;
-					  }
-
-						if (isset($props['length']))
-							$rfields[$field]['length'] = $props['length'];
-
-						if (isset($props['notnull']))
-						  $rfields[$field]['notnull'] = $props['notnull'] ? true : false;
-
-						if (isset($props['default']))
-							$rfields[$field]['default'] = $props['default'];
-
-						if (isset($props['index'])) $indexes[] = $field;
-						if (isset($props['unique'])) $uniques[] = $field;
-						if (isset($props['primary'])) $pk[$field] = '';
-					}
-
-          if (!isset($fields['created'])) $fields['created'] = null;
-          if (!isset($fields['no_dates'])) $fields['no_dates'] = null;
-          if (!isset($fields['modified'])) $fields['modified'] = null;
-          
-					if ($fields['created'] !== false &amp;&amp; $fields['no_dates'] !== true)
-					{
-						$rfields['created']['type'] = 'timestamp';
-						$rfields['created']['notnull'] = false;
-						$rfields['created']['default'] = NULL;
-					}
-					if ($fields['modified'] !== false &amp;&amp; $fields['no_dates'] !== true)
-					{
-						$rfields['modified']['type'] = 'timestamp';
-						$rfields['modified']['notnull'] = false;
-						$rfields['modified']['default'] = NULL;
-					}
-					
-					if (isset($fields['fkey']))
-					{
-					  $rfields[$fields['fkey'].'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-					  $indexes[] = $fields['fkey'].'_id';
-					}
-					if (isset($fields['fkeys']))
-					{
-					  foreach($fields['fkeys'] as $key)
-					  {
-					    $rfields[$key.'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-					    $indexes[] = $key.'_id';
-				    }
-					}
-
-					$r = $this-&gt;_db-&gt;createTable($table, $rfields, array('primary'=&gt;$pk));
-					if (PEAR::isError($r)) $this-&gt;err($r-&gt;getUserInfo());
-					
-					if (count($indexes) &gt; 0)
-					{
-						foreach ($indexes as $field)
-						{
-							$r = $this-&gt;_db-&gt;createIndex($table, $field, array(
-								'fields' =&gt; array($field=&gt;array())
-							));
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-					if (count($uniques) &gt; 0)
-					{
-						foreach ($uniques as $field)
-						{
-							$r = $this-&gt;_db-&gt;createConstraint($table, $field.'_unq', array(
-								'unique' =&gt; true,
-								'fields' =&gt; array($field =&gt; array())
-							));
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-				}
-			}
-			elseif ($name == 'drop_table' || $name == 'drop_tables')
-			{
-				if (is_array($action))
-				{
-					foreach ($action as $table)
-					{
-						$this-&gt;out(&quot;      &gt; dropping table '$table'&quot;);
-						$r = $this-&gt;_db-&gt;dropTable($table);
-						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					}
-				}
-				else
-				{
-					$this-&gt;out(&quot;      &gt; dropping table '$action'&quot;);
-					$r = $this-&gt;_db-&gt;dropTable($action);
-					if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-				}
-			}
-			elseif ($name == 'add_fields' || $name == 'add_field' || $name == 'add_columns' || $name == 'add_column')
-			{
-				/*
-				 * Valid fields: text, integer, blob, boolean, float, date, time, timestamp(datetime)
-				 * Read: http://cvs.php.net/viewcvs.cgi/pear/MDB2/docs/datatypes.html?view=co
-				 */
-				foreach ($action as $table=&gt;$fields)
-				{
-					$rfields = array();
-					$indexes = array();
-					$uniques = array();
-					$pk = array();
-					
-          foreach ($fields as $field =&gt; $props)
-          {
-            $this-&gt;out(&quot;      &gt; adding column '$field' on '$table'&quot;);
-            
-            if (preg_match(&quot;/^created|modified|fkey|fkeys$/&quot;, $field)) continue;
-          
-            if (!empty($props)) $props = $this-&gt;_getProperties($props);
-          
-            if (preg_match(&quot;/\\_id$/&quot;, $field) &amp;&amp; count($props) &lt; 1)
-            {
-              $rfields[$field] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-              continue;
+        if (!count($this-&gt;unmigrated_migrations) &amp;&amp; $this-&gt;current_migration['id'] == $this-&gt;target_migration['id']) {
+            $this-&gt;out('');
+            $this-&gt;out('  ** Migrations are up to date **');
+            $this-&gt;out('');
+            $this-&gt;hr();
+            $this-&gt;out('');
+            exit;
+        }
+
+        $direction = ($this-&gt;target_migration['id'] &lt; $this-&gt;current_migration['id']) ? 'down' : 'up';
+        $this-&gt;_sortMigrations($direction);
+
+        $this-&gt;out('');
+        $this-&gt;out(&quot;Migrating database $direction from version #{$this-&gt;current_migration['id']} to #{$this-&gt;target_migration['id']} ...&quot;);
+        $this-&gt;out('');
+        
+        foreach ($this-&gt;migrations as $migration) {
+            if ($direction == 'up') {
+                if ($migration['migrated']) continue;
+                if ($migration['id'] &gt; $this-&gt;target_migration['id']) break;
+            } else {
+                if (!$migration['migrated']) continue;
+                if ($migration['id'] == $this-&gt;target_migration['id']) break;
             }
-          
-            if ($props['type'] == 'int')
-            {
-              $props['type'] = 'integer';
-              $rfields[$field]['type'] = 'integer';
+
+            $this-&gt;out(&quot;  [{$migration['id']}] {$migration['name']} ...&quot;);
+
+            $res = $this-&gt;_startMigration($migration['id'], $direction);
+            if ($res == 1) {
+                $this-&gt;out('');
+                $time = gmdate(&quot;U&quot;);
+                if ($direction == 'up') {
+                    $r = $this-&gt;_db-&gt;exec(&quot;INSERT INTO {$this-&gt;schema_table} SET version = {$migration['id']}, datetime = $time&quot;);
+                    if (PEAR::isError($r)) {
+                        $this-&gt;err($r-&gt;getDebugInfo());
+                    } else {
+                        $this-&gt;migrations[$migration['id']]['migrated'] = true;
+                        $this-&gt;migrations[$migration['id']]['migrated_on'] = $time;
+                    }
+                } else {
+                    $r = $this-&gt;_db-&gt;exec(&quot;DELETE FROM {$this-&gt;schema_table} WHERE version = {$migration['id']}&quot;);
+                    if (PEAR::isError($r)) {
+                        $this-&gt;err($r-&gt;getDebugInfo());
+                    } else {
+                        $this-&gt;migrations[$migration['id']]['migrated'] = false;
+                        $this-&gt;migrations[$migration['id']]['migrated_on'] = '';
+                    }
+                }
+            } else {
+                $this-&gt;out(&quot;  ERROR: $res&quot;);
+                $this-&gt;hr();
+                return;
             }
-            
-            if ($props['type'] == 'bool')
-            {
-              $props['type'] = 'boolean';
-              $rfields[$field]['type'] = 'boolean';
+        }
+    }
+
+    function _startMigration($id, $direction)
+    {
+        $migration = $this-&gt;migrations[$id];
+        if ($migration['format'] == 'yml') {
+            $yml = $this-&gt;_parsePhp(MIGRATIONS_PATH .DS. $migration['filename']);
+            if (function_exists('syck_load')) {
+                $array = syck_load($yml);
+            } else {
+                vendor('Spyc');
+                $array = Spyc::YAMLLoad($yml);
             }
-          
-            $props['type'] = isset($props['type']) ? $props['type'] : 'string';
-            $rfields[$field]['type'] = $props['type'];
-            if ($props['type'] == 'string')
-            {
-             $rfields[$field]['type'] = 'text';
-             if (!isset($props['length'])) $rfields[$field]['length'] = 255;
+            if (!is_array($array)) return &quot;Unable to parse YAML Migration file&quot;;
+            $direction = strtoupper($direction);
+        } else {
+            include MIGRATIONS_PATH .DS. $migration['filename'];
+            $array = $migration;
+            unset($migration);
+        }
+
+        if (!$array[$direction]) return &quot;Direction does not exist!&quot;;
+        return $this-&gt;_array2Sql($array[$direction]);
+    }
+
+    function _getProperties($props)
+    {
+        $_props = array();
+        if (!is_array($props)) $props = array($props);
+
+        foreach ($props as $prop) {
+            switch ($prop) {
+            case is_numeric($prop):
+                $_props['length'] = $prop;
+                break;
+            case 'is_null':
+            case 'isnull':
+                $_props['notnull'] = false;
+                break;
+            case 'not_null':
+            case 'notnull':
+                $_props['notnull'] = true;
+                break;
+            case in_array($prop, $this-&gt;types):
+                $_props['type'] = $prop;
+                break;
+            case 'index':
+                $_props['index'] = true;
+                break;
+            case 'unique':
+                $_props['unique'] = true;
+                break;
+            case 'primary':
+                $_props['primary'] = true;
+                break;
+            case 'no_dates':
+                $_props['no_dates'] = true;
+                break;
+            case 'no_id':
+                $_props['no_id'] = true;
+                break;
+            default:
+                $_props['default'] = $prop;
+                break;
             }
+        }
+        if (!array_key_exists('type', $_props)) $_props['type'] = 'string';
+        return $_props;
+    }
+
+    function _array2Sql($array)
+    {
+        foreach ($array as $name=&gt;$action) {
+            switch ($name) {
+                case 'create_table':
+                case 'create_tables':
+                    foreach ($action as $table=&gt;$fields) {
+                        $this-&gt;out(&quot;      &gt; creating table '$table'&quot;);
+
+                        $rfields = array();
+                        $table_props = array();
+                        $indexes = array();
+                        $uniques = array();
+                        $pk = array();
+                    
+                        if (isset($fields[0])) $fields = am($fields, $this-&gt;_getProperties($fields[0]));
+                        unset($fields[0]);
+
+                        if (!isset($fields['no_id'])) {
+                            $rfields['id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+                        }
+                    
+                        foreach ($fields as $field=&gt;$props) {
+                            if (preg_match(&quot;/^no_id|created|modified|no_dates|fkey|fkeys$/&quot;, $field)) continue;
+                        
+                            if (!empty($props)) $props = $this-&gt;_getProperties($props);
+
+                            if (preg_match(&quot;/\\_id$/&quot;, $field) &amp;&amp; count($props) &lt; 1) {
+                                $rfields[$field] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+                                $indexes[] = $field;
+                                continue;
+                            }
+
+                            if ($props['type'] == 'int') {
+                                $props['type'] = 'integer';
+                                $rfields[$field]['type'] = 'integer';
+                            }
+
+                            if ($props['type'] == 'bool') {
+                                $props['type'] = 'boolean';
+                                $rfields[$field]['type'] = 'boolean';
+                            }
+
+                            if ($props['type'] == 'fkey') {
+                                $rfields[$field.'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+                                $indexes[] = $field.'_id';
+                                continue;
+                            }
+
+                            $props['type'] = isset($props['type']) ? $props['type'] : 'string';
+                            $rfields[$field]['type'] = $props['type'];
+                            if ($props['type'] == 'string') {
+                                $rfields[$field]['type'] = 'text';
+                                if (!isset($props['length'])) $rfields[$field]['length'] = 255;
+                            }
+
+                            if (isset($props['length'])) $rfields[$field]['length'] = $props['length'];
+
+                            if (isset($props['notnull'])) $rfields[$field]['notnull'] = $props['notnull'] ? true : false;
+
+                            if (isset($props['default'])) $rfields[$field]['default'] = $props['default'];
+
+                            if (isset($props['index'])) $indexes[] = $field;
+                            if (isset($props['unique'])) $uniques[] = $field;
+                            if (isset($props['primary'])) $pk[$field] = '';
+                        }
+
+                        if (!isset($fields['created'])) $fields['created'] = null;
+                        if (!isset($fields['no_dates'])) $fields['no_dates'] = null;
+                        if (!isset($fields['modified'])) $fields['modified'] = null;
           
-            if (isset($props['length']))
-             $rfields[$field]['length'] = $props['length'];
-          
-            if (isset($props['notnull']))
-             $rfields[$field]['notnull'] = $props['notnull'] ? true : false;
-          
-            if (isset($props['default']))
-             $rfields[$field]['default'] = $props['default'];
-          
-            if (isset($props['index'])) $indexes[] = $field;
-            if (isset($props['unique'])) $uniques[] = $field;
-            if (isset($props['primary'])) $pk[$field] = '';
-          }
-					
-          if (isset($fields['created']) || isset($fields['modified']))
-          {
-            $rfields[$field]['type'] = 'timestamp';
-            $rfields[$field]['notnull'] = false;
-            $rfields[$field]['default'] = NULL;
-          }
-					
-					if (isset($fields['fkey'])) $rfields[$fields['fkey'].'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-					if (isset($fields['fkeys'])) foreach($fields['fkeys'] as $key) $rfields[$key.'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
-
-					$r = $this-&gt;_db-&gt;alterTable($table, array('add'=&gt;$rfields), false);
-					if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					
-					if ($pk)
-					{
-						$r = $this-&gt;_db-&gt;createConstraint($table, $pk, array(
-							'primary' =&gt; true,
-							'fields' =&gt; array($pk =&gt; array())
-						));
-						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					}
-					
-					if (count($indexes) &gt; 0)
-					{
-						foreach ($indexes as $field)
-						{
-							$r = $this-&gt;_db-&gt;createIndex($table, $field, array(
-								'fields' =&gt; array($field =&gt; array())
-							));
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-					
-					if (count($uniques) &gt; 0)
-					{
-						foreach ($uniques as $field)
-						{
-							$r = $this-&gt;_db-&gt;createConstraint($table, $field.'_unq', array(
-								'unique' =&gt; true,
-								'fields' =&gt; array($field =&gt; array())
-							));
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-				}
-			}
-			elseif ($name == 'drop_fields' || $name == 'drop_field' || $name == 'drop_columns' || $name == 'drop_column')
-			{
-				foreach ($action as $table=&gt;$fields)
-				{
-					if (is_array($fields))
-					{
-						foreach($fields as $nil=&gt;$field)
-						{
-						  $this-&gt;out(&quot;      &gt; dropping column '$field' on '$table'&quot;);
-						  $rfields[$field] = array();
-					  }
-						$r = $this-&gt;_db-&gt;alterTable($table, array('remove'=&gt;$rfields), false);
-						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					}
-					else
-					{
-						$this-&gt;out(&quot;      &gt; adding column '$fields' on '$table'&quot;);
-						$r = $this-&gt;_db-&gt;alterTable($table, array('remove'=&gt;array($fields=&gt;array())), false);
-						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					}
-				}
-			}
-			elseif ($name == 'rename_table' || $name == 'rename_tables')
-			{
-				foreach ($action as $current_name =&gt; $new_name)
-				{
-					$this-&gt;out(&quot;      &gt; renaming table '$current_name' to '$new_name'&quot;);
-					$r = $this-&gt;_db-&gt;alterTable($current_name, array('name'=&gt;$new_name), false);
-				  if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-			  }
-		  }
-			elseif ($name == 'rename_field' || $name == 'rename_fields' || $name == 'rename_column' || $name == 'rename_columns')
-			{
-				foreach ($action as $table =&gt; $fields)
-				{
-					foreach($fields as $field =&gt; $new_name)
-					{
-					  $this-&gt;out(&quot;      &gt; renaming column '$field' to '$new_name' on '$table'&quot;);
-
-						$r = $this-&gt;_db-&gt;getTableFieldDefinition($table, $field);
-						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						
-					  $change = array(
-					    $field =&gt; array(
-					      'name' =&gt; $new_name,
-					      'definition' =&gt; $r[0]
-					    )
-					  );
-					  
-					  $r = $this-&gt;_db-&gt;alterTable($table, array('rename'=&gt;$change), false);
-					  if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-				  }
-			  }
-		  }
-			elseif ($name == 'alter_field' || $name == 'alter_fields' || $name == 'alter_column' || $name == 'alter_columns')
-			{
-				foreach ($action as $table=&gt;$fields)
-				{
-					$change = array();
-					$indexes = array();
-					$uniques = array();
-					$pk = null;
-					$Nindexes = array();
-					$Nuniques = array();
-					$Npks = array();
-
-					foreach($fields as $field=&gt;$props)
-					{
-					  $this-&gt;out(&quot;      &gt; altering column '$field' on '$table'&quot;);
-					  
-					  $props = $this-&gt;_getProperties($props);
-					  $rfields = array();
-					  
-						if (!isset($props['type']))
-						{
-							$r = $this-&gt;_db-&gt;getTableFieldDefinition($table, $field);
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-							$props['type'] = $r[0]['mdb2type'];
-							if (!isset($props['length'])) $props['length'] = $r[0]['length'];
-						}
-						
-            $props['type'] = isset($props['type']) ? $props['type'] : 'string';
-            $rfields['type'] = $props['type'];
-            
-            if (isset($props['length'])) $rfields['length'] = $props['length'];
-            
-            if ($props['type'] == 'string')
-            {
-              $rfields['type'] = 'text';
-              if (!isset($props['length'])) $rfields['length'] = 255;
+                        if ($fields['created'] !== false &amp;&amp; $fields['no_dates'] !== true) {
+                            $rfields['created']['type'] = 'timestamp';
+                            $rfields['created']['notnull'] = false;
+                            $rfields['created']['default'] = NULL;
+                        }
+                        if ($fields['modified'] !== false &amp;&amp; $fields['no_dates'] !== true) {
+                            $rfields['modified']['type'] = 'timestamp';
+                            $rfields['modified']['notnull'] = false;
+                            $rfields['modified']['default'] = NULL;
+                        }
+                    
+                        if (isset($fields['fkey'])) {
+                            $rfields[$fields['fkey'] . '_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+                            $indexes[] = $fields['fkey'] . '_id';
+                        }
+                        if (isset($fields['fkeys'])) {
+                            foreach($fields['fkeys'] as $key) {
+                                $rfields[$key . '_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+                                $indexes[] = $key . '_id';
+                            }
+                        }
+
+                        $r = $this-&gt;_db-&gt;createTable($table, $rfields, array('primary' =&gt; $pk));
+                        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getUserInfo());
+                    
+                        if (count($indexes) &gt; 0) {
+                            foreach ($indexes as $field) {
+                                $r = $this-&gt;_db-&gt;createIndex($table, $field, array(
+                                    'fields' =&gt; array($field=&gt;array())
+                                ));
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                        if (count($uniques) &gt; 0) {
+                            foreach ($uniques as $field) {
+                                $r = $this-&gt;_db-&gt;createConstraint($table, $field.'_unq', array(
+                                    'unique' =&gt; true,
+                                    'fields' =&gt; array($field =&gt; array())
+                                ));
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    }
+                    break;
+                case 'drop_table':
+                case 'drop_tables':
+                    if (is_array($action)) {
+                        foreach ($action as $table) {
+                            $this-&gt;out(&quot;      &gt; dropping table '$table'&quot;);
+                            $r = $this-&gt;_db-&gt;dropTable($table);
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        }
+                    } else {
+                        $this-&gt;out(&quot;      &gt; dropping table '$action'&quot;);
+                        $r = $this-&gt;_db-&gt;dropTable($action);
+                        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                    }
+                    break;
+                case 'add_fields':
+                case 'add_field':
+                case 'add_columns':
+                case 'add_column':
+                    foreach ($action as $table=&gt;$fields) {
+                        $rfields = array();
+                        $indexes = array();
+                        $uniques = array();
+                        $pk = array();
+                    
+                        foreach ($fields as $field =&gt; $props) {
+                            $this-&gt;out(&quot;      &gt; adding column '$field' on '$table'&quot;);
+
+                            if (preg_match(&quot;/^created|modified|fkey|fkeys$/&quot;, $field)) continue;
+
+                            if (!empty($props)) $props = $this-&gt;_getProperties($props);
+
+                            if (preg_match(&quot;/\\_id$/&quot;, $field) &amp;&amp; count($props) &lt; 1) {
+                                $rfields[$field] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+                                continue;
+                            }
+
+                            if ($props['type'] == 'int') {
+                                $props['type'] = 'integer';
+                                $rfields[$field]['type'] = 'integer';
+                            }
+
+                            if ($props['type'] == 'bool') {
+                                $props['type'] = 'boolean';
+                                $rfields[$field]['type'] = 'boolean';
+                            }
+
+                            $props['type'] = isset($props['type']) ? $props['type'] : 'string';
+                            $rfields[$field]['type'] = $props['type'];
+                            if ($props['type'] == 'string') {
+                                $rfields[$field]['type'] = 'text';
+                                if (!isset($props['length'])) $rfields[$field]['length'] = 255;
+                            }
+
+                            if (isset($props['length'])) $rfields[$field]['length'] = $props['length'];
+
+                            if (isset($props['notnull'])) $rfields[$field]['notnull'] = $props['notnull'] ? true : false;
+
+                            if (isset($props['default'])) $rfields[$field]['default'] = $props['default'];
+
+                            if (isset($props['index'])) $indexes[] = $field;
+                            if (isset($props['unique'])) $uniques[] = $field;
+                            if (isset($props['primary'])) $pk[$field] = '';
+                        }
+                    
+                        if (isset($fields['created']) || isset($fields['modified'])) {
+                            $rfields[$field]['type'] = 'timestamp';
+                            $rfields[$field]['notnull'] = false;
+                            $rfields[$field]['default'] = NULL;
+                        }
+                    
+                        if (isset($fields['fkey'])) $rfields[$fields['fkey'].'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+                        if (isset($fields['fkeys'])) foreach($fields['fkeys'] as $key) $rfields[$key.'_id'] = $this-&gt;use_uuid ? $this-&gt;uuid_format : $this-&gt;id_format;
+
+                        $r = $this-&gt;_db-&gt;alterTable($table, array('add'=&gt;$rfields), false);
+                        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                    
+                        if ($pk) {
+                            $r = $this-&gt;_db-&gt;createConstraint($table, $pk, array(
+                                'primary' =&gt; true,
+                                'fields' =&gt; array($pk =&gt; array())
+                            ));
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        }
+                    
+                        if (count($indexes) &gt; 0) {
+                            foreach ($indexes as $field) {
+                                $r = $this-&gt;_db-&gt;createIndex($table, $field, array(
+                                    'fields' =&gt; array($field =&gt; array())
+                                ));
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    
+                        if (count($uniques) &gt; 0) {
+                            foreach ($uniques as $field) {
+                                $r = $this-&gt;_db-&gt;createConstraint($table, $field.'_unq', array(
+                                    'unique' =&gt; true,
+                                    'fields' =&gt; array($field =&gt; array())
+                                ));
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    }
+                    break;
+                case 'drop_fields':
+                case 'drop_field':
+                case 'drop_columns':
+                case 'drop_column':
+                    foreach ($action as $table=&gt;$fields) {
+                        if (is_array($fields)) {
+                            foreach($fields as $nil=&gt;$field) {
+                                $this-&gt;out(&quot;      &gt; dropping column '$field' on '$table'&quot;);
+                                $rfields[$field] = array();
+                            }
+                            $r = $this-&gt;_db-&gt;alterTable($table, array('remove'=&gt;$rfields), false);
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        } else {
+                            $this-&gt;out(&quot;      &gt; adding column '$fields' on '$table'&quot;);
+                            $r = $this-&gt;_db-&gt;alterTable($table, array('remove'=&gt;array($fields=&gt;array())), false);
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        }
+                    }
+                    break;
+                case 'rename_table':
+                case 'rename_tables':
+                    foreach ($action as $current_name =&gt; $new_name) {
+                        $this-&gt;out(&quot;      &gt; renaming table '$current_name' to '$new_name'&quot;);
+                        $r = $this-&gt;_db-&gt;alterTable($current_name, array('name'=&gt;$new_name), false);
+                        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                    }
+                    break;
+                case 'rename_field':
+                case 'rename_fields':
+                case 'rename_column':
+                case 'rename_columns':
+                    foreach ($action as $table =&gt; $fields) {
+                        foreach($fields as $field =&gt; $new_name) {
+                            $this-&gt;out(&quot;      &gt; renaming column '$field' to '$new_name' on '$table'&quot;);
+
+                            $r = $this-&gt;_db-&gt;getTableFieldDefinition($table, $field);
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        
+                            $change = array(
+                                $field =&gt; array(
+                                    'name' =&gt; $new_name,
+                                    'definition' =&gt; $r[0]
+                                )
+                            );
+                      
+                            $r = $this-&gt;_db-&gt;alterTable($table, array('rename'=&gt;$change), false);
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        }
+                    }
+                    break;
+                case 'alter_field':
+                case 'alter_fields':
+                case 'alter_column':
+                case 'alter_columns':
+                    foreach ($action as $table=&gt;$fields) {
+                        $change = array();
+                        $indexes = array();
+                        $uniques = array();
+                        $pk = null;
+                        $Nindexes = array();
+                        $Nuniques = array();
+                        $Npks = array();
+
+                        foreach($fields as $field=&gt;$props) {
+                            $this-&gt;out(&quot;      &gt; altering column '$field' on '$table'&quot;);
+                      
+                            $props = $this-&gt;_getProperties($props);
+                            $rfields = array();
+                      
+                            if (!isset($props['type'])) {
+                                $r = $this-&gt;_db-&gt;getTableFieldDefinition($table, $field);
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                                $props['type'] = $r[0]['mdb2type'];
+                                if (!isset($props['length'])) $props['length'] = $r[0]['length'];
+                            }
+                        
+                            $props['type'] = isset($props['type']) ? $props['type'] : 'string';
+                            $rfields['type'] = $props['type'];
+
+                            if (isset($props['length'])) $rfields['length'] = $props['length'];
+
+                            if ($props['type'] == 'string') {
+                                $rfields['type'] = 'text';
+                                if (!isset($props['length'])) $rfields['length'] = 255;
+                            }
+
+                            if (isset($props['length'])) $rfields['length'] = $props['length'];
+
+                            if (isset($props['notnull'])) $rfields['notnull'] = $props['notnull'] ? true : false;
+
+                            if (isset($props['default'])) $rfields['default'] = $props['default'];
+
+                            if (isset($props['index']) &amp;&amp; $props['index'] === true) $indexes[] = $field;
+                            if (isset($props['unique']) &amp;&amp; $props['unique'] === true) $uniques[] = $field;
+                            if (isset($props['primary']) &amp;&amp; $props['primary'] === true) $pk = $field;
+        
+                            if (isset($props['index']) &amp;&amp; $props['index'] === false) $Nindexes[] = $field;
+                            if (isset($props['unique']) &amp;&amp; $props['unique'] === false) $Nuniques[] = $field;
+                            if (isset($props['primary']) &amp;&amp; $props['primary'] === false) $Npks[] = $field;
+                        
+                            $change[$field]['definition'] = $rfields;
+                        }
+                    
+                        $r = $this-&gt;_db-&gt;alterTable($table, array('change'=&gt;$change), false);
+                        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                    
+                        if ($Npks) {
+                            foreach ($Npks as $field) {
+                                $r = $this-&gt;_db-&gt;dropConstraint($table, $Npk, true);
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    
+                        if ($pk) {
+                            $r = $this-&gt;_db-&gt;createConstraint($table, $pk, array(
+                                'primary' =&gt; true,
+                                'fields' =&gt; array($pk =&gt; array())
+                            ));
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        }
+                    
+                        if (count($Nindexes) &gt; 0) {
+                            foreach ($Nindexes as $field) {
+                                $r = $this-&gt;_db-&gt;dropIndex($table, $field);
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    
+                        if (count($indexes) &gt; 0) {
+                            foreach ($indexes as $field) {
+                                $r = $this-&gt;_db-&gt;createIndex($table, $field, array(
+                                    'fields' =&gt; array($field=&gt;array())
+                                ));
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    
+                        if (count($Nuniques) &gt; 0) {
+                            foreach ($Nuniques as $field) {
+                                $r = $this-&gt;_db-&gt;dropConstraint($table, $field);
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    
+                        if (count($uniques) &gt; 0) {
+                            foreach ($uniques as $field) {
+                                $r = $this-&gt;_db-&gt;createConstraint($table, $field, array(
+                                    'unique' =&gt; true,
+                                    'fields' =&gt; array($field=&gt;array())
+                                ));
+                                if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                            }
+                        }
+                    }
+                    break;
+                case 'query':
+                case 'queries':
+                    if (is_array($action)) {
+                        foreach ($action as $sql) {
+                            $this-&gt;out(&quot;      &gt; running SQL&quot;);
+                            $r = $this-&gt;_db-&gt;query($sql);
+                            if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                        }
+                    } else {
+                        $this-&gt;out(&quot;      &gt; running SQL&quot;);
+                        $r = $this-&gt;_db-&gt;query($action);
+                        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
+                    }
+                    break;
             }
-          
-            if (isset($props['length'])) $rfields['length'] = $props['length'];
-          
-            if (isset($props['notnull'])) $rfields['notnull'] = $props['notnull'] ? true : false;
-          
-            if (isset($props['default'])) $rfields['default'] = $props['default'];
-            
-            if (isset($props['index']) &amp;&amp; $props['index'] === true) $indexes[] = $field;
-            if (isset($props['unique']) &amp;&amp; $props['unique'] === true) $uniques[] = $field;
-            if (isset($props['primary']) &amp;&amp; $props['primary'] === true) $pk = $field;
-						
-            if (isset($props['index']) &amp;&amp; $props['index'] === false) $Nindexes[] = $field;
-            if (isset($props['unique']) &amp;&amp; $props['unique'] === false) $Nuniques[] = $field;
-            if (isset($props['primary']) &amp;&amp; $props['primary'] === false) $Npks[] = $field;
-						
-						$change[$field]['definition'] = $rfields;
-					}
-					
-					$r = $this-&gt;_db-&gt;alterTable($table, array('change'=&gt;$change), false);
-					if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					
-					if ($Npks)
-					{
-						foreach ($Npks as $field)
-						{
-  						$r = $this-&gt;_db-&gt;dropConstraint($table, $Npk, true);
-  						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					  }
-					}
-					
-					if ($pk)
-					{
-						$r = $this-&gt;_db-&gt;createConstraint($table, $pk, array(
-							'primary'=&gt;true,
-							'fields'=&gt;
-								array($pk=&gt;array())
-						));
-						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					}
-					
-					if (count($Nindexes) &gt; 0)
-					{
-						foreach ($Nindexes as $field)
-						{
-							$r = $this-&gt;_db-&gt;dropIndex($table, $field);
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-					
-					if (count($indexes) &gt; 0)
-					{
-						foreach ($indexes as $field)
-						{
-							$r = $this-&gt;_db-&gt;createIndex($table, $field, array(
-								'fields'=&gt;
-									array($field=&gt;array())
-							));
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-					
-					if (count($Nuniques) &gt; 0)
-					{
-						foreach ($Nuniques as $field)
-						{
-							$r = $this-&gt;_db-&gt;dropConstraint($table, $field);
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-					
-					if (count($uniques) &gt; 0)
-					{
-						foreach ($uniques as $field)
-						{
-							$r = $this-&gt;_db-&gt;createConstraint($table, $field, array(
-								'unique'=&gt;true,
-								'fields'=&gt;
-									array($field=&gt;array())
-							));
-							if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-						}
-					}
-				}
-			}
-			elseif ($name == 'query' || $name == 'queries')
-			{
-				if (is_array($action))
-				{
-					foreach ($action as $sql)
-					{
-						$this-&gt;out(&quot;      &gt; running SQL&quot;);
-						$r = $this-&gt;_db-&gt;query($sql);
-						if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-					}
-				}
-				else
-				{
-				  $this-&gt;out(&quot;      &gt; running SQL&quot;);
-					$r = $this-&gt;_db-&gt;query($action);
-					if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-				}
-			}
-		}
-		return 1;
-	}
-
-	function _upMigrations($a, $b)
-	{
-		list($aStr) = explode('_', $a);
-		list($bStr) = explode('_', $b);
-		$aNum = (int)$aStr;
-		$bNum = (int)$bStr;
-		if ($aNum == $bNum) {
-			return 0;
-		}
-		return ($aNum &gt; $bNum) ? 1 : -1;
-	}
-
-	function _downMigrations($a, $b)
-	{
-		list($aStr) = explode('_', $a);
-		list($bStr) = explode('_', $b);
-		$aNum = (int)$aStr;
-		$bNum = (int)$bStr;
-		if ($aNum == $bNum) {
-			return 0;
-		}
-		return ($aNum &gt; $bNum) ? -1 : 1;
-	}
-
-	function _initDatabase()
-	{
-		if (!@include_once('MDB2.php')) $this-&gt;error('PEAR NOT FOUND', &quot;Unable to include PEAR.php and MDB2.php\n&quot;);
-
-		if (!$this-&gt;_loadDbConfig()) exit;
-
-		$config = $this-&gt;DbConfig-&gt;{$this-&gt;dataSource};
-		$dsn = array(
-		    'phptype'   =&gt;	$config['driver'],
-		    'username'	=&gt;	$config['login'],
-		    'password'	=&gt;	$config['password'],
-		    'hostspec'	=&gt;	$config['host'],
-		    'database'	=&gt;	$config['database']
-		);
-		$options = array(
-			'debug' 		=&gt;	'DEBUG',
-			'portability'	=&gt;	'DB_PORTABILITY_ALL'
-		);
-		$this-&gt;_db = &amp;MDB2::connect($dsn, $options);
-		if (PEAR::isError($this-&gt;_db)) $this-&gt;error('MDB2 ERROR', $this-&gt;_db-&gt;getDebugInfo());
-		$this-&gt;_db-&gt;setFetchMode(MDB2_FETCHMODE_ASSOC);
-		$this-&gt;_db-&gt;loadModule('Manager');
-		$this-&gt;_db-&gt;loadModule('Extended');
-		$this-&gt;_db-&gt;loadModule('Reverse');	
-	}
-
-	function _getMigrationVersion()
-	{
-		$r = $tables = $this-&gt;_db-&gt;listTables();
-		if (PEAR::isError($r)) $this-&gt;err($r-&gt;getMessage());
-
-		if (!in_array('schema_info', $tables))
-		{
-			$this-&gt;out('Creating migrations version table (\'schema_info\') ...', false);
-
-			$this-&gt;_db-&gt;createTable('schema_info', array(
-				'version'	=&gt;	array(
-					'type'		=&gt;	'integer',
-					'unsigned'	=&gt;	1,
-					'notnull'	=&gt;	1,
-					'default'	=&gt;	0
-				)
-			));
-			$r = $this-&gt;_db-&gt;autoExecute('schema_info', array('version'=&gt;0), MDB2_AUTOQUERY_INSERT, null, array('integer'));
-			if (PEAR::isError($r)) $this-&gt;err($r-&gt;getDebugInfo());
-
-			$this-&gt;out('CREATED!');
-		}
-
-		$version = $this-&gt;_db-&gt;queryOne(&quot;SELECT version FROM schema_info&quot;);
-		$this-&gt;current_version = $version;
-		settype($this-&gt;current_version, 'integer');
-	}
-
-	function _getMigrations()
-	{
-		$folder = new Folder(MIGRATIONS_PATH, true, 0777);
-		$this-&gt;migrations = $folder-&gt;find(&quot;[0-9]+_.+\.yml&quot;);
-		usort($this-&gt;migrations, array($this, '_upMigrations'));
-		$this-&gt;migration_count = count($this-&gt;migrations);
-	}
-
-	function _parsePhp($file)
-	{
-		ob_start();
-		include ($file);
-		$buf = ob_get_contents();
-		ob_end_clean();
-		return $buf;
-	}
-	
-	/**
-	 * Gives the user an option to open a specified file in Textmate
-	 *
-	 * @param string $file a file that will be opened with Textmate
-	 */
-	function _mate($file)
-	{
-	  $this-&gt;out('');
-	  if (strtoupper($this-&gt;in(&quot;  Do you want to edit this file now with Textmate?&quot;, array('Y', 'N'), 'Y')) == 'Y')
-	  {
-	    system('mate '. $file);
+        }
+        return 1;
+    }
+
+    function _sortMigrations($dir = 'up')
+    {
+        if ($dir == 'up') {
+            asort($this-&gt;migrations);
+        } else {
+            arsort($this-&gt;migrations);
+        }
+    }
+
+    function _initDatabase()
+    {
+        if (!@include_once('MDB2.php')) $this-&gt;error('PEAR NOT FOUND', &quot;Unable to include PEAR.php and MDB2.php\n&quot;);
+
+        if (!$this-&gt;_loadDbConfig()) exit;
+
+        $config = $this-&gt;DbConfig-&gt;{$this-&gt;dataSource};
+        $dsn = array(
+            'phptype'   =&gt;  $config['driver'],
+            'username'  =&gt;  $config['login'],
+            'password'  =&gt;  $config['password'],
+            'hostspec'  =&gt;  $config['host'],
+            'database'  =&gt;  $config['database']
+        );
+        $options = array(
+            'debug'         =&gt;  'DEBUG',
+            'portability'   =&gt;  'DB_PORTABILITY_ALL'
+        );
+        $this-&gt;_db = &amp;MDB2::connect($dsn, $options);
+        if (PEAR::isError($this-&gt;_db)) $this-&gt;error('MDB2 ERROR', $this-&gt;_db-&gt;getDebugInfo());
+        $this-&gt;_db-&gt;setFetchMode(MDB2_FETCHMODE_ASSOC);
+        $this-&gt;_db-&gt;loadModule('Manager');
+        $this-&gt;_db-&gt;loadModule('Extended');
+        $this-&gt;_db-&gt;loadModule('Reverse');  
+    }
+
+    function _getMigrations()
+    {
+        $r = $tables = $this-&gt;_db-&gt;listTables();
+        if (PEAR::isError($r)) $this-&gt;err($r-&gt;getMessage());
+
+        if (!in_array($this-&gt;schema_table, $tables)) {
+            $this-&gt;out(&quot;Creating migrations version table ('{$this-&gt;schema_table}') ...&quot;, false);
+            $this-&gt;_db-&gt;createTable($this-&gt;schema_table, array(
+                'version'   =&gt;  array(
+                    'type'      =&gt;  'integer',
+                    'unsigned'  =&gt;  1,
+                    'notnull'   =&gt;  1,
+                    'default'   =&gt;  0
+                ),
+                'datetime'   =&gt;  array(
+                    'type'      =&gt;  'integer',
+                    'unsigned'  =&gt;  1,
+                    'notnull'   =&gt;  1,
+                    'default'   =&gt;  0
+                )
+            ));
+            $this-&gt;out('CREATED!');
+        }
+
+        $folder = new Folder(MIGRATIONS_PATH, true, 0777);
+        $files = $folder-&gt;find(&quot;[0-9]+_.+\.(yml|php)&quot;);
+        $db = array();
+        foreach ($this-&gt;_db-&gt;queryAll(&quot;SELECT * FROM {$this-&gt;schema_table}&quot;) as $row) {
+            $db[$row['version']] = $row['datetime'];
+        }
+
+        foreach ($files as $file) {
+            preg_match(&quot;/^([0-9]+)\_(.+)\.(yml|php)$/&quot;, $file, $match);
+            $id = $match[1];
+            $migrated = isset($db[$id]);
+            $this-&gt;migrations[$id] = array(
+                'id' =&gt; $id,
+                'name' =&gt; Inflector::humanize($match[2]),
+                'filename' =&gt; $file,
+                'format' =&gt; $match[3],
+                'migrated' =&gt; $migrated,
+                'migrated_on' =&gt; ($migrated) ? $db[$id] : ''
+            );
+            if (!$migrated) $this-&gt;unmigrated_migrations[] = $id;
+        }
+        
+        $this-&gt;_sortMigrations();
+        
+        foreach ($this-&gt;migrations as $migration) {
+            if ($migration['migrated']) {
+                $this-&gt;current_migration = $migration;
+            }
+        }
+        
+        $this-&gt;target_migration = end($this-&gt;migrations);
+    }
+
+    function _parsePhp($file)
+    {
+        ob_start();
+        include  $file;
+        $buf = ob_get_contents();
+        ob_end_clean();
+        return $buf;
     }
-    $this-&gt;out('');
-	}
-	
+    
+    /**
+     * Gives the user an option to open a specified file in Textmate
+     *
+     * @param string $file a file that will be opened with Textmate
+     */
+    function _mate($file)
+    {
+        $this-&gt;out('');
+        if (strtoupper($this-&gt;in(&quot;  Do you want to edit this file now with Textmate?&quot;, array('Y', 'N'), 'Y')) == 'Y') {
+            system('mate '. $file);
+        }
+        $this-&gt;out('');
+    }
+    
   /**
    * Modifies the out method for prettier formatting
    *
    * @param string $string String to output.
    * @param boolean $newline If true, the outputs gets an added newline.
    */
-	function out($string, $newline = true) {
-		return parent::out(&quot;  &quot;.$string, $newline);
-	}
-	
-  /**
-   * Converts migration number to a minimum three digit number.
-   *
-   * @param $num The number to convert
-   * @return $num The converted three digit number
-   */
-  function _versionIt($num)
-  {
-    switch (strlen($num))
+    function out($string, $newline = true) {
+        return parent::out(&quot;  &quot;.$string, $newline);
+    }
+    
+    /**
+    * Converts migration number to a minimum three digit number.
+    *
+    * @param $num The number to convert
+    * @return $num The converted three digit number
+    */
+    function _versionIt($num)
+    {
+        switch (strlen($num)) {
+            case 1:
+                return '00'.$num;
+            case 2:
+                return '0'.$num;
+            default:
+                return $num;
+        }
+    }
+    
+    /**
+     * Help method
+     */
+    function help()
     {
-      case 1:
-        return '00'.$num;
-      case 2:
-        return '0'.$num;
-      default:
-        return $num;
+        $this-&gt;hr();
+        $this-&gt;out('');
+        $this-&gt;out('Database migrations is a version control system for your database,');
+        $this-&gt;out('allowing you to migrate your database schema between versions.');
+        $this-&gt;out('');
+        $this-&gt;out('Each version is depicted by a migration file written in YAML and must');
+        $this-&gt;out('include an UP and DOWN section. The UP section is parsed and run when');
+        $this-&gt;out('migrating up and vice versa.');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+        $this-&gt;out('COMMAND LINE OPTIONS');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate');
+        $this-&gt;out('    - Migrates to the latest version (the last migration file)');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate [version number]');
+        $this-&gt;out('    - Migrates to the version specified [version number]');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate generate|gen|g [migration name]');
+        $this-&gt;out('    - Generates a migration file with the given name [migration name]');
+        $this-&gt;out('      [migration name] must be alphanumeric, but can include spaces,');
+        $this-&gt;out('      hyphens and underscores.');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate generate|gen|g from db [table1 table2 ...]');
+        $this-&gt;out('    - Generates a migration file for the specified table(s). The YAML is ');
+        $this-&gt;out('      generated from the actual database table.');
+        $this-&gt;out('      If no tables are passed, it generates one single migration file ');
+        $this-&gt;out('      called full_schema.yml using your current database tables.');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate generate|gen|g sessions');
+        $this-&gt;out('    - Generates the cake sessions table.');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate generate|gen|g create table_name');
+        $this-&gt;out('    - Generates a migration file that will create a table with the given');
+        $this-&gt;out('      underscored table_name.');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate from_schema');
+        $this-&gt;out('    - Runs and migrates the full_schema.yml migration file if it exists.');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate reset');
+        $this-&gt;out('    - Drops all tables and resets the current version to 0');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate all');
+        $this-&gt;out('    - Migrates down to 0 and back up to the latest version');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate down [version]');
+        $this-&gt;out('    - Migrates down to the previous current version. If [version] is specified');
+        $this-&gt;out('      will run the DOWN section only on that specified version.');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate up [version]');
+        $this-&gt;out('    - Migrates up to the previous current version. If [version] is specified');
+        $this-&gt;out('      will run the UP section only on that specified version.');
+        $this-&gt;out('');
+        $this-&gt;out('  cake migrate help');
+        $this-&gt;out('    - Displays this Help');
+        $this-&gt;out('');
+        $this-&gt;out(&quot;    append '-ds [data source]' to the command if you want to specify the&quot;);
+        $this-&gt;out('    datasource to use from database.php');
+        $this-&gt;out('');
+        $this-&gt;out('');
+        $this-&gt;out('For more information and for the latest release of this and others,');
+        $this-&gt;out('go to http://developingwithstyle.com');
+        $this-&gt;out('');
+        $this-&gt;hr();
+        $this-&gt;out('');
+    }
+    
+    /**
+     * Aliases for help method
+     */
+    function h() { $this-&gt;help(); }
+    
+    function _welcome()
+    {
+        $this-&gt;out('');
+        $this-&gt;out(' __  __  _  _  __     ___     __   __   __  ___    __  _  _  __ ');
+        $this-&gt;out('|   |__| |_/  |__    | | | | | _  |__| |__|  |  | |  | |\ | |__ ');
+        $this-&gt;out('|__ |  | | \_ |__    | | | | |__| | \_ |  |  |  | |__| | \|  __|');
+        $this-&gt;out('');
     }
-  }
-	
-	/**
-	 * Help method
-	 */
-	function help()
-	{
-	  $this-&gt;hr();
-	  $this-&gt;out('');
-    $this-&gt;out('Database migrations is a version control system for your database,');
-    $this-&gt;out('allowing you to migrate your database schema between versions.');
-    $this-&gt;out('');
-    $this-&gt;out('Each version is depicted by a migration file written in YAML and must');
-    $this-&gt;out('include an UP and DOWN section. The UP section is parsed and run when');
-    $this-&gt;out('migrating up and vice versa.');
-    $this-&gt;out('');
-    $this-&gt;hr();
-    $this-&gt;out('');
-    $this-&gt;out('COMMAND LINE OPTIONS');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate');
-    $this-&gt;out('    - Migrates to the latest version (the last migration file)');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate [version number]');
-    $this-&gt;out('    - Migrates to the version specified [version number]');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate generate|gen|g [migration name]');
-    $this-&gt;out('    - Generates a migration file with the given name [migration name]');
-    $this-&gt;out('');
-    $this-&gt;out('      [migration name] must be alphanumeric, but can include spaces,');
-    $this-&gt;out('      hyphens and underscores.');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate generate|gen|g from db [table1 table2 ...]');
-    $this-&gt;out('    - Generates a migration file for the specified table(s). The YAML is ');
-    $this-&gt;out('      generated from the actual database table.');
-    $this-&gt;out('');
-    $this-&gt;out('      If no tables are passed, it generates one single migration file ');
-    $this-&gt;out('      called full_schema.yml using your current database tables.');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate generate|gen|g sessions');
-    $this-&gt;out('    - Generates the cake sessions table.');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate generate|gen|g create table_name');
-    $this-&gt;out('    - Generates a migration file that will create a table with the given');
-    $this-&gt;out('      underscored table_name.');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate from_schema');
-    $this-&gt;out('    - Runs and migrates the full_schema.yml migration file if it exists.');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate reset');
-    $this-&gt;out('    - Drops all tables and resets the current version to 0');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate all');
-    $this-&gt;out('    - Migrates down to 0 and back up o the latest version');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate down');
-    $this-&gt;out('    - Migrates down to the previous current version');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate up');
-    $this-&gt;out('    - Migrates up from the current to the next version');
-    $this-&gt;out('');
-    $this-&gt;out('  cake migrate help');
-    $this-&gt;out('    - Displays this Help');
-    $this-&gt;out('');
-    $this-&gt;out(&quot;    append '-ds [data source]' to the command if you want to specify the&quot;);
-    $this-&gt;out('    datasource to use from database.php');
-    $this-&gt;out('');
-    $this-&gt;out('');
-    $this-&gt;out('For more information and for the latest release of this and others,');
-    $this-&gt;out('go to http://joelmoss.info');
-    $this-&gt;out('');
-    $this-&gt;hr();
-    $this-&gt;out('');
-	}
-	
-	/**
-	 * Aliases for help method
-	 */
-	function h() { $this-&gt;help(); }
-	
-	function _welcome()
-	{
-		$this-&gt;out('');
-    $this-&gt;out(' __  __  _  _  __     ___     __   __   __  ___    __  _  _  __ ');
-    $this-&gt;out('|   |__| |_/  |__    | | | | | _  |__| |__|  |  | |  | |\ | |__ ');
-    $this-&gt;out('|__ |  | | \_ |__    | | | | |__| | \_ |  |  |  | |__| | \|  __|');
-		$this-&gt;out('');
-	}
   
 }
 
 function is_assoc_array($array)
 {
-  if ( is_array($array) &amp;&amp; !empty($array) )
-  {
-    for ( $iterator = count($array) - 1; $iterator; $iterator-- )
-    {
-      if ( !array_key_exists($iterator, $array) ) return true;
+    if ( is_array($array) &amp;&amp; !empty($array) ) {
+        for ( $iterator = count($array) - 1; $iterator; $iterator-- ) {
+            if ( !array_key_exists($iterator, $array) ) return true;
+        }
+        return !array_key_exists(0, $array);
     }
-    return !array_key_exists(0, $array);
-  }
-  return false;
+    return false;
 }
 
 ?&gt;</diff>
      <filename>vendors/shells/migrate.php</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>ef8ebca411b0ac453c81d54c2970c4170619d5d5</id>
    </parent>
  </parents>
  <author>
    <name>joel@developwithstyle.com</name>
    <email>joel@developwithstyle.com</email>
  </author>
  <url>http://github.com/joelmoss/cakephp-db-migrations/commit/3ff270f99e6d4a7375b83eda1a00e3ed447f53d2</url>
  <id>3ff270f99e6d4a7375b83eda1a00e3ed447f53d2</id>
  <committed-date>2008-05-20T06:56:05-07:00</committed-date>
  <authored-date>2008-05-20T06:56:05-07:00</authored-date>
  <message>First beta release of Migrations v4.0</message>
  <tree>02ddaccec098de432668189546edbbb2ce1cc906</tree>
  <committer>
    <name>joel@developwithstyle.com</name>
    <email>joel@developwithstyle.com</email>
  </committer>
</commit>
