| <?php defined('BASEPATH') OR exit('No direct script access allowed'); | 
| /** | 
|  * CodeIgniter | 
|  * | 
|  * An open source application development framework for PHP 5.1.6 or newer | 
|  * | 
|  * @package        CodeIgniter | 
|  * @author        EllisLab Dev Team | 
|  * @copyright    Copyright (c) 2006 - 2012, EllisLab, Inc. | 
|  * @license        http://codeigniter.com/user_guide/license.html | 
|  * @link        http://codeigniter.com | 
|  * @since        Version 1.0 | 
|  * @filesource | 
|  */ | 
|   | 
| // ------------------------------------------------------------------------ | 
|   | 
| /** | 
|  * Migration Class | 
|  * | 
|  * All migrations should implement this, forces up() and down() and gives | 
|  * access to the CI super-global. | 
|  * | 
|  * @package        CodeIgniter | 
|  * @subpackage    Libraries | 
|  * @category    Libraries | 
|  * @author        Reactor Engineers | 
|  * @link | 
|  */ | 
| class CI_Migration { | 
|   | 
|     protected $_migration_enabled = FALSE; | 
|     protected $_migration_path = NULL; | 
|     protected $_migration_version = 0; | 
|   | 
|     protected $_error_string = ''; | 
|   | 
|     public function __construct($config = array()) | 
|     { | 
|         # Only run this constructor on main library load | 
|         if (get_parent_class($this) !== FALSE) | 
|         { | 
|             return; | 
|         } | 
|   | 
|         foreach ($config as $key => $val) | 
|         { | 
|             $this->{'_' . $key} = $val; | 
|         } | 
|   | 
|         log_message('debug', 'Migrations class initialized'); | 
|   | 
|         // Are they trying to use migrations while it is disabled? | 
|         if ($this->_migration_enabled !== TRUE) | 
|         { | 
|             show_error('Migrations has been loaded but is disabled or set up incorrectly.'); | 
|         } | 
|   | 
|         // If not set, set it | 
|         $this->_migration_path == '' AND $this->_migration_path = APPPATH . 'migrations/'; | 
|   | 
|         // Add trailing slash if not set | 
|         $this->_migration_path = rtrim($this->_migration_path, '/').'/'; | 
|   | 
|         // Load migration language | 
|         $this->lang->load('migration'); | 
|   | 
|         // They'll probably be using dbforge | 
|         $this->load->dbforge(); | 
|   | 
|         // If the migrations table is missing, make it | 
|         if ( ! $this->db->table_exists('migrations')) | 
|         { | 
|             $this->dbforge->add_field(array( | 
|                 'version' => array('type' => 'INT', 'constraint' => 3), | 
|             )); | 
|   | 
|             $this->dbforge->create_table('migrations', TRUE); | 
|   | 
|             $this->db->insert('migrations', array('version' => 0)); | 
|         } | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Migrate to a schema version | 
|      * | 
|      * Calls each migration step required to get to the schema version of | 
|      * choice | 
|      * | 
|      * @param    int    Target schema version | 
|      * @return    mixed    TRUE if already latest, FALSE if failed, int if upgraded | 
|      */ | 
|     public function version($target_version) | 
|     { | 
|         $start = $current_version = $this->_get_version(); | 
|         $stop = $target_version; | 
|   | 
|         if ($target_version > $current_version) | 
|         { | 
|             // Moving Up | 
|             ++$start; | 
|             ++$stop; | 
|             $step = 1; | 
|         } | 
|         else | 
|         { | 
|             // Moving Down | 
|             $step = -1; | 
|         } | 
|   | 
|         $method = ($step === 1) ? 'up' : 'down'; | 
|         $migrations = array(); | 
|   | 
|         // We now prepare to actually DO the migrations | 
|         // But first let's make sure that everything is the way it should be | 
|         for ($i = $start; $i != $stop; $i += $step) | 
|         { | 
|             $f = glob(sprintf($this->_migration_path . '%03d_*.php', $i)); | 
|   | 
|             // Only one migration per step is permitted | 
|             if (count($f) > 1) | 
|             { | 
|                 $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $i); | 
|                 return FALSE; | 
|             } | 
|   | 
|             // Migration step not found | 
|             if (count($f) == 0) | 
|             { | 
|                 // If trying to migrate up to a version greater than the last | 
|                 // existing one, migrate to the last one. | 
|                 if ($step == 1) | 
|                 { | 
|                     break; | 
|                 } | 
|   | 
|                 // If trying to migrate down but we're missing a step, | 
|                 // something must definitely be wrong. | 
|                 $this->_error_string = sprintf($this->lang->line('migration_not_found'), $i); | 
|                 return FALSE; | 
|             } | 
|   | 
|             $file = basename($f[0]); | 
|             $name = basename($f[0], '.php'); | 
|   | 
|             // Filename validations | 
|             if (preg_match('/^\d{3}_(\w+)$/', $name, $match)) | 
|             { | 
|                 $match[1] = strtolower($match[1]); | 
|   | 
|                 // Cannot repeat a migration at different steps | 
|                 if (in_array($match[1], $migrations)) | 
|                 { | 
|                     $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]); | 
|                     return FALSE; | 
|                 } | 
|   | 
|                 include $f[0]; | 
|                 $class = 'Migration_' . ucfirst($match[1]); | 
|   | 
|                 if ( ! class_exists($class)) | 
|                 { | 
|                     $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class); | 
|                     return FALSE; | 
|                 } | 
|   | 
|                 if ( ! is_callable(array($class, $method))) | 
|                 { | 
|                     $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class); | 
|                     return FALSE; | 
|                 } | 
|   | 
|                 $migrations[] = $match[1]; | 
|             } | 
|             else | 
|             { | 
|                 $this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file); | 
|                 return FALSE; | 
|             } | 
|         } | 
|   | 
|         log_message('debug', 'Current migration: ' . $current_version); | 
|   | 
|         $version = $i + ($step == 1 ? -1 : 0); | 
|   | 
|         // If there is nothing to do so quit | 
|         if ($migrations === array()) | 
|         { | 
|             return TRUE; | 
|         } | 
|   | 
|         log_message('debug', 'Migrating from ' . $method . ' to version ' . $version); | 
|   | 
|         // Loop through the migrations | 
|         foreach ($migrations AS $migration) | 
|         { | 
|             // Run the migration class | 
|             $class = 'Migration_' . ucfirst(strtolower($migration)); | 
|             call_user_func(array(new $class, $method)); | 
|   | 
|             $current_version += $step; | 
|             $this->_update_version($current_version); | 
|         } | 
|   | 
|         log_message('debug', 'Finished migrating to '.$current_version); | 
|   | 
|         return $current_version; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Set's the schema to the latest migration | 
|      * | 
|      * @return    mixed    true if already latest, false if failed, int if upgraded | 
|      */ | 
|     public function latest() | 
|     { | 
|         if ( ! $migrations = $this->find_migrations()) | 
|         { | 
|             $this->_error_string = $this->lang->line('migration_none_found'); | 
|             return false; | 
|         } | 
|   | 
|         $last_migration = basename(end($migrations)); | 
|   | 
|         // Calculate the last migration step from existing migration | 
|         // filenames and procceed to the standard version migration | 
|         return $this->version((int) substr($last_migration, 0, 3)); | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Set's the schema to the migration version set in config | 
|      * | 
|      * @return    mixed    true if already current, false if failed, int if upgraded | 
|      */ | 
|     public function current() | 
|     { | 
|         return $this->version($this->_migration_version); | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Error string | 
|      * | 
|      * @return    string    Error message returned as a string | 
|      */ | 
|     public function error_string() | 
|     { | 
|         return $this->_error_string; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Set's the schema to the latest migration | 
|      * | 
|      * @return    mixed    true if already latest, false if failed, int if upgraded | 
|      */ | 
|     protected function find_migrations() | 
|     { | 
|         // Load all *_*.php files in the migrations path | 
|         $files = glob($this->_migration_path . '*_*.php'); | 
|         $file_count = count($files); | 
|   | 
|         for ($i = 0; $i < $file_count; $i++) | 
|         { | 
|             // Mark wrongly formatted files as false for later filtering | 
|             $name = basename($files[$i], '.php'); | 
|             if ( ! preg_match('/^\d{3}_(\w+)$/', $name)) | 
|             { | 
|                 $files[$i] = FALSE; | 
|             } | 
|         } | 
|   | 
|         sort($files); | 
|         return $files; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Retrieves current schema version | 
|      * | 
|      * @return    int    Current Migration | 
|      */ | 
|     protected function _get_version() | 
|     { | 
|         $row = $this->db->get('migrations')->row(); | 
|         return $row ? $row->version : 0; | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Stores the current schema version | 
|      * | 
|      * @param    int    Migration reached | 
|      * @return    bool | 
|      */ | 
|     protected function _update_version($migrations) | 
|     { | 
|         return $this->db->update('migrations', array( | 
|             'version' => $migrations | 
|         )); | 
|     } | 
|   | 
|     // -------------------------------------------------------------------- | 
|   | 
|     /** | 
|      * Enable the use of CI super-global | 
|      * | 
|      * @param    mixed    $var | 
|      * @return    mixed | 
|      */ | 
|     public function __get($var) | 
|     { | 
|         return get_instance()->$var; | 
|     } | 
| } | 
|   | 
| /* End of file Migration.php */ | 
| /* Location: ./system/libraries/Migration.php */ |