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