public static function migrate($fromVersion, $toVersion, $tableName)
 {
     if (!is_object($fromVersion)) {
         $fromVersion = new VersionItem($fromVersion);
     }
     if (!is_object($toVersion)) {
         $toVersion = new VersionItem($toVersion);
     }
     if ($fromVersion->getStamp() == $toVersion->getStamp()) {
         return;
         // nothing to do
     }
     if ($fromVersion->getStamp() < $toVersion->getStamp()) {
         $toMigration = self::createClass($toVersion, $tableName);
         if (!is_null($toMigration)) {
             // morph the table structure
             if (method_exists($toMigration, 'morph')) {
                 $toMigration->morph();
             }
             // modify the datasets
             if (method_exists($toMigration, 'up')) {
                 $toMigration->up();
                 // we don't need the afterUp function anymore!
                 //if (method_exists($toMigration, 'afterUp')) {
                 //    $toMigration->afterUp();
                 //}
             }
         }
     } else {
         // rollback!
         // reset the data modifications
         $fromMigration = self::createClass($fromVersion, $tableName);
         if (!is_null($fromMigration) && method_exists($fromMigration, 'down')) {
             $fromMigration->down();
         }
         // call the last morph function in the previous migration files
         $toMigration = self::createPrevClassWithMorphMethod($toVersion, $tableName);
         if (!is_null($toMigration)) {
             if (method_exists($toMigration, 'morph')) {
                 $toMigration->morph();
             }
         } else {
             self::$_connection->dropTable($tableName);
         }
     }
 }