PageRenderTime 40ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/system/libraries/Migration.php

https://bitbucket.org/fusioninvoice_it/fusioninvoice
PHP | 338 lines | 163 code | 59 blank | 116 comment | 21 complexity | 2691743f122166ed2127a52404dbc69f MD5 | raw file
  1. <?php defined('BASEPATH') OR exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author EllisLab Dev Team
  9. * @copyright Copyright (c) 2006 - 2012, EllisLab, Inc.
  10. * @license http://codeigniter.com/user_guide/license.html
  11. * @link http://codeigniter.com
  12. * @since Version 1.0
  13. * @filesource
  14. */
  15. // ------------------------------------------------------------------------
  16. /**
  17. * Migration Class
  18. *
  19. * All migrations should implement this, forces up() and down() and gives
  20. * access to the CI super-global.
  21. *
  22. * @package CodeIgniter
  23. * @subpackage Libraries
  24. * @category Libraries
  25. * @author Reactor Engineers
  26. * @link
  27. */
  28. class CI_Migration {
  29. protected $_migration_enabled = FALSE;
  30. protected $_migration_path = NULL;
  31. protected $_migration_version = 0;
  32. protected $_error_string = '';
  33. public function __construct($config = array())
  34. {
  35. # Only run this constructor on main library load
  36. if (get_parent_class($this) !== FALSE)
  37. {
  38. return;
  39. }
  40. foreach ($config as $key => $val)
  41. {
  42. $this->{'_' . $key} = $val;
  43. }
  44. log_message('debug', 'Migrations class initialized');
  45. // Are they trying to use migrations while it is disabled?
  46. if ($this->_migration_enabled !== TRUE)
  47. {
  48. show_error('Migrations has been loaded but is disabled or set up incorrectly.');
  49. }
  50. // If not set, set it
  51. $this->_migration_path == '' OR $this->_migration_path = APPPATH . 'migrations/';
  52. // Add trailing slash if not set
  53. $this->_migration_path = rtrim($this->_migration_path, '/').'/';
  54. // Load migration language
  55. $this->lang->load('migration');
  56. // They'll probably be using dbforge
  57. $this->load->dbforge();
  58. // If the migrations table is missing, make it
  59. if ( ! $this->db->table_exists('migrations'))
  60. {
  61. $this->dbforge->add_field(array(
  62. 'version' => array('type' => 'INT', 'constraint' => 3),
  63. ));
  64. $this->dbforge->create_table('migrations', TRUE);
  65. $this->db->insert('migrations', array('version' => 0));
  66. }
  67. }
  68. // --------------------------------------------------------------------
  69. /**
  70. * Migrate to a schema version
  71. *
  72. * Calls each migration step required to get to the schema version of
  73. * choice
  74. *
  75. * @access public
  76. * @param $version integer Target schema version
  77. * @return mixed TRUE if already latest, FALSE if failed, int if upgraded
  78. */
  79. public function version($target_version)
  80. {
  81. $start = $current_version = $this->_get_version();
  82. $stop = $target_version;
  83. if ($target_version > $current_version)
  84. {
  85. // Moving Up
  86. ++$start;
  87. ++$stop;
  88. $step = 1;
  89. }
  90. else
  91. {
  92. // Moving Down
  93. $step = -1;
  94. }
  95. $method = $step === 1 ? 'up' : 'down';
  96. $migrations = array();
  97. // We now prepare to actually DO the migrations
  98. // But first let's make sure that everything is the way it should be
  99. for ($i = $start; $i != $stop; $i += $step)
  100. {
  101. $f = glob(sprintf($this->_migration_path . '%03d_*.php', $i));
  102. // Only one migration per step is permitted
  103. if (count($f) > 1)
  104. {
  105. $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $i);
  106. return FALSE;
  107. }
  108. // Migration step not found
  109. if (count($f) == 0)
  110. {
  111. // If trying to migrate up to a version greater than the last
  112. // existing one, migrate to the last one.
  113. if ($step == 1)
  114. {
  115. break;
  116. }
  117. // If trying to migrate down but we're missing a step,
  118. // something must definitely be wrong.
  119. $this->_error_string = sprintf($this->lang->line('migration_not_found'), $i);
  120. return FALSE;
  121. }
  122. $file = basename($f[0]);
  123. $name = basename($f[0], '.php');
  124. // Filename validations
  125. if (preg_match('/^\d{3}_(\w+)$/', $name, $match))
  126. {
  127. $match[1] = strtolower($match[1]);
  128. // Cannot repeat a migration at different steps
  129. if (in_array($match[1], $migrations))
  130. {
  131. $this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]);
  132. return FALSE;
  133. }
  134. include $f[0];
  135. $class = 'Migration_' . ucfirst($match[1]);
  136. if ( ! class_exists($class))
  137. {
  138. $this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class);
  139. return FALSE;
  140. }
  141. if ( ! is_callable(array($class, $method)))
  142. {
  143. $this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class);
  144. return FALSE;
  145. }
  146. $migrations[] = $match[1];
  147. }
  148. else
  149. {
  150. $this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file);
  151. return FALSE;
  152. }
  153. }
  154. log_message('debug', 'Current migration: ' . $current_version);
  155. $version = $i + ($step == 1 ? -1 : 0);
  156. // If there is nothing to do so quit
  157. if ($migrations === array())
  158. {
  159. return TRUE;
  160. }
  161. log_message('debug', 'Migrating from ' . $method . ' to version ' . $version);
  162. // Loop through the migrations
  163. foreach ($migrations AS $migration)
  164. {
  165. // Run the migration class
  166. $class = 'Migration_' . ucfirst(strtolower($migration));
  167. call_user_func(array(new $class, $method));
  168. $current_version += $step;
  169. $this->_update_version($current_version);
  170. }
  171. log_message('debug', 'Finished migrating to '.$current_version);
  172. return $current_version;
  173. }
  174. // --------------------------------------------------------------------
  175. /**
  176. * Set's the schema to the latest migration
  177. *
  178. * @access public
  179. * @return mixed true if already latest, false if failed, int if upgraded
  180. */
  181. public function latest()
  182. {
  183. if ( ! $migrations = $this->find_migrations())
  184. {
  185. $this->_error_string = $this->line->lang('migration_none_found');
  186. return false;
  187. }
  188. $last_migration = basename(end($migrations));
  189. // Calculate the last migration step from existing migration
  190. // filenames and procceed to the standard version migration
  191. return $this->version((int) substr($last_migration, 0, 3));
  192. }
  193. // --------------------------------------------------------------------
  194. /**
  195. * Set's the schema to the migration version set in config
  196. *
  197. * @access public
  198. * @return mixed true if already current, false if failed, int if upgraded
  199. */
  200. public function current()
  201. {
  202. return $this->version($this->_migration_version);
  203. }
  204. // --------------------------------------------------------------------
  205. /**
  206. * Error string
  207. *
  208. * @access public
  209. * @return string Error message returned as a string
  210. */
  211. public function error_string()
  212. {
  213. return $this->_error_string;
  214. }
  215. // --------------------------------------------------------------------
  216. /**
  217. * Set's the schema to the latest migration
  218. *
  219. * @access protected
  220. * @return mixed true if already latest, false if failed, int if upgraded
  221. */
  222. protected function find_migrations()
  223. {
  224. // Load all *_*.php files in the migrations path
  225. $files = glob($this->_migration_path . '*_*.php');
  226. $file_count = count($files);
  227. for ($i = 0; $i < $file_count; $i++)
  228. {
  229. // Mark wrongly formatted files as false for later filtering
  230. $name = basename($files[$i], '.php');
  231. if ( ! preg_match('/^\d{3}_(\w+)$/', $name))
  232. {
  233. $files[$i] = FALSE;
  234. }
  235. }
  236. sort($files);
  237. return $files;
  238. }
  239. // --------------------------------------------------------------------
  240. /**
  241. * Retrieves current schema version
  242. *
  243. * @access protected
  244. * @return integer Current Migration
  245. */
  246. protected function _get_version()
  247. {
  248. $row = $this->db->get('migrations')->row();
  249. return $row ? $row->version : 0;
  250. }
  251. // --------------------------------------------------------------------
  252. /**
  253. * Stores the current schema version
  254. *
  255. * @access protected
  256. * @param $migrations integer Migration reached
  257. * @return void Outputs a report of the migration
  258. */
  259. protected function _update_version($migrations)
  260. {
  261. return $this->db->update('migrations', array(
  262. 'version' => $migrations
  263. ));
  264. }
  265. // --------------------------------------------------------------------
  266. /**
  267. * Enable the use of CI super-global
  268. *
  269. * @access public
  270. * @param $var
  271. * @return mixed
  272. */
  273. public function __get($var)
  274. {
  275. return get_instance()->$var;
  276. }
  277. }
  278. /* End of file Migration.php */
  279. /* Location: ./system/libraries/Migration.php */